diff options
993 files changed, 22102 insertions, 10936 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2f843f9d6164..8547ec164084 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -1809,12 +1809,25 @@ aconfig_declarations { name: "aconfig_settingslib_flags", package: "com.android.settingslib.flags", container: "system", + exportable: true, srcs: [ "packages/SettingsLib/aconfig/settingslib.aconfig", ], } java_aconfig_library { + name: "aconfig_settingslib_exported_flags_java_lib", + aconfig_declarations: "aconfig_settingslib_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], + mode: "exported", + min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], +} + +java_aconfig_library { name: "aconfig_settingslib_flags_java_lib", aconfig_declarations: "aconfig_settingslib_flags", defaults: ["framework-minus-apex-aconfig-java-defaults"], diff --git a/MEMORY_OWNERS b/MEMORY_OWNERS index 89ce5140d8ea..12aa2951bbc9 100644 --- a/MEMORY_OWNERS +++ b/MEMORY_OWNERS @@ -2,5 +2,4 @@ surenb@google.com tjmercier@google.com kaleshsingh@google.com jyescas@google.com -carlosgalo@google.com jji@google.com diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java index c77528021201..ed669beae1ce 100644 --- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java @@ -63,12 +63,14 @@ public class ZipFilePerfTest { @Test @Parameters(method = "getData") - public void timeZipFileOpenClose(int numEntries) throws Exception { + public void timeZipFileOpen(int numEntries) throws Exception { setUp(numEntries); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ZipFile zf = new ZipFile(mFile); + state.pauseTiming(); zf.close(); + state.resumeTiming(); } } diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig index 63624d8cad4a..8b1a40c7f833 100644 --- a/apex/jobscheduler/framework/aconfig/job.aconfig +++ b/apex/jobscheduler/framework/aconfig/job.aconfig @@ -55,3 +55,14 @@ flag { description: "Introduce a new getPendingJobReasonsHistory() API which returns a limited historical view of getPendingJobReasons()." bug: "372031023" } + + +flag { + name: "add_type_info_to_wakelock_tag" + namespace: "backstage_power" + description: "Append the job type info to wakelock tag" + bug: "381880530" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 4335cae65a3c..fe6daa57ecd0 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -5766,6 +5766,41 @@ public class JobSchedulerService extends com.android.server.SystemService } // Shell command infrastructure + int getJobWakelockTag(PrintWriter pw, String pkgName, int userId, @Nullable String namespace, + int jobId) { + try { + final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, + userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM); + if (uid < 0) { + pw.print("unknown("); + pw.print(pkgName); + pw.println(")"); + return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE; + } + + synchronized (mLock) { + final JobStatus js = mJobs.getJobByUidAndJobId(uid, namespace, jobId); + if (DEBUG) { + Slog.d(TAG, "get-job-wakelock-tag " + namespace + + "/" + uid + "/" + jobId + ": " + js); + } + if (js == null) { + pw.print("unknown("); + UserHandle.formatUid(pw, uid); + pw.print("/jid"); + pw.print(jobId); + pw.println(")"); + return JobSchedulerShellCommand.CMD_ERR_NO_JOB; + } + + pw.println(js.getWakelockTag()); + } + } catch (RemoteException e) { + // can't happen + } + return 0; + } + int getJobState(PrintWriter pw, String pkgName, int userId, @Nullable String namespace, int jobId) { try { @@ -5945,6 +5980,9 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(android.app.job.Flags.FLAG_GET_PENDING_JOB_REASONS_HISTORY_API, android.app.job.Flags.getPendingJobReasonsHistoryApi()); pw.println(); + pw.print(android.app.job.Flags.FLAG_ADD_TYPE_INFO_TO_WAKELOCK_TAG, + android.app.job.Flags.addTypeInfoToWakelockTag()); + pw.println(); pw.decreaseIndent(); pw.println(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index 42c8250a6185..633598e85fa9 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -86,6 +86,8 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return getTransferredNetworkBytes(pw, BYTE_OPTION_DOWNLOAD); case "get-transferred-upload-bytes": return getTransferredNetworkBytes(pw, BYTE_OPTION_UPLOAD); + case "get-job-wakelock-tag": + return getJobWakelockTag(pw); case "get-job-state": return getJobState(pw); case "heartbeat": @@ -424,6 +426,9 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { case android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS: pw.println(android.app.job.Flags.jobDebugInfoApis()); break; + case android.app.job.Flags.FLAG_ADD_TYPE_INFO_TO_WAKELOCK_TAG: + pw.println(android.app.job.Flags.addTypeInfoToWakelockTag()); + break; case com.android.server.job.Flags.FLAG_BATCH_ACTIVE_BUCKET_JOBS: pw.println(com.android.server.job.Flags.batchActiveBucketJobs()); break; @@ -581,6 +586,49 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { } } + private int getJobWakelockTag(PrintWriter pw) throws Exception { + checkPermission("get job wakelock tag"); + + int userId = UserHandle.USER_SYSTEM; + String namespace = null; + + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "-u": + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + + case "-n": + case "--namespace": + namespace = getNextArgRequired(); + break; + + default: + pw.println("Error: unknown option '" + opt + "'"); + return -1; + } + } + + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + final String pkgName = getNextArgRequired(); + final String jobIdStr = getNextArgRequired(); + final int jobId = Integer.parseInt(jobIdStr); + + final long ident = Binder.clearCallingIdentity(); + try { + int ret = mInternal.getJobWakelockTag(pw, pkgName, userId, namespace, jobId); + printError(ret, pkgName, userId, namespace, jobId); + return ret; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private int getJobState(PrintWriter pw) throws Exception { checkPermission("get job state"); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 5a33aa0ab7eb..4b9d7364e27b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -1459,7 +1459,12 @@ public final class JobStatus { @NonNull public String getWakelockTag() { if (mWakelockTag == null) { - mWakelockTag = "*job*/" + this.batteryName; + mWakelockTag = "*job*"; + if (android.app.job.Flags.addTypeInfoToWakelockTag()) { + mWakelockTag += (isRequestedExpeditedJob() + ? "e" : (getJob().isUserInitiated() ? "u" : "r")); + } + mWakelockTag += "/" + this.batteryName; } return mWakelockTag; } diff --git a/api/api.go b/api/api.go index e4d783eba4c3..cbdb7e81ab86 100644 --- a/api/api.go +++ b/api/api.go @@ -105,7 +105,7 @@ func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.WalkDeps(func(child, parent android.Module) bool { - if _, ok := child.(java.AndroidLibraryDependency); ok && child.Name() != "framework-res" { + if _, ok := android.OtherModuleProvider(ctx, child, java.AndroidLibraryInfoProvider); ok && child.Name() != "framework-res" { // Stubs of BCP and SSCP libraries should not have any dependencies on apps // This check ensures that we do not run into circular dependencies when UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT=true ctx.ModuleErrorf( diff --git a/boot/Android.bp b/boot/Android.bp index eaa984ac0cdd..f4ef1df96bc5 100644 --- a/boot/Android.bp +++ b/boot/Android.bp @@ -76,8 +76,8 @@ custom_platform_bootclasspath { module: "art-bootclasspath-fragment", }, { - apex: "com.android.btservices", - module: "com.android.btservices-bootclasspath-fragment", + apex: "com.android.bt", + module: "com.android.bt-bootclasspath-fragment", }, { apex: "com.android.configinfrastructure", diff --git a/core/api/current.txt b/core/api/current.txt index 32507dfef9b6..7c56a5811abb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9190,37 +9190,37 @@ package android.app.blob { package android.app.jank { @FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public final class AppJankStats { - ctor public AppJankStats(int, @NonNull String, @Nullable String, @Nullable String, long, long, @NonNull android.app.jank.FrameOverrunHistogram); - method @NonNull public android.app.jank.FrameOverrunHistogram getFrameOverrunHistogram(); + ctor public AppJankStats(int, @NonNull String, @Nullable String, @Nullable String, long, long, @NonNull android.app.jank.RelativeFrameTimeHistogram); method public long getJankyFrameCount(); + method @NonNull public android.app.jank.RelativeFrameTimeHistogram getRelativeFrameTimeHistogram(); method public long getTotalFrameCount(); method public int getUid(); method @NonNull public String getWidgetCategory(); method @NonNull public String getWidgetId(); method @NonNull public String getWidgetState(); - field public static final String ANIMATING = "animating"; - field public static final String ANIMATION = "animation"; - field public static final String DRAGGING = "dragging"; - field public static final String FLINGING = "flinging"; - field public static final String KEYBOARD = "keyboard"; - field public static final String MEDIA = "media"; - field public static final String NAVIGATION = "navigation"; - field public static final String NONE = "none"; - field public static final String OTHER = "other"; - field public static final String PLAYBACK = "playback"; - field public static final String PREDICTIVE_BACK = "predictive_back"; - field public static final String SCROLL = "scroll"; - field public static final String SCROLLING = "scrolling"; - field public static final String SWIPING = "swiping"; - field public static final String TAPPING = "tapping"; - field public static final String WIDGET_CATEGORY_UNSPECIFIED = "widget_category_unspecified"; - field public static final String WIDGET_STATE_UNSPECIFIED = "widget_state_unspecified"; - field public static final String ZOOMING = "zooming"; - } - - @FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public class FrameOverrunHistogram { - ctor public FrameOverrunHistogram(); - method public void addFrameOverrunMillis(int); + field public static final String WIDGET_CATEGORY_ANIMATION = "animation"; + field public static final String WIDGET_CATEGORY_KEYBOARD = "keyboard"; + field public static final String WIDGET_CATEGORY_MEDIA = "media"; + field public static final String WIDGET_CATEGORY_NAVIGATION = "navigation"; + field public static final String WIDGET_CATEGORY_OTHER = "other"; + field public static final String WIDGET_CATEGORY_SCROLL = "scroll"; + field public static final String WIDGET_CATEGORY_UNSPECIFIED = "unspecified"; + field public static final String WIDGET_STATE_ANIMATING = "animating"; + field public static final String WIDGET_STATE_DRAGGING = "dragging"; + field public static final String WIDGET_STATE_FLINGING = "flinging"; + field public static final String WIDGET_STATE_NONE = "none"; + field public static final String WIDGET_STATE_PLAYBACK = "playback"; + field public static final String WIDGET_STATE_PREDICTIVE_BACK = "predictive_back"; + field public static final String WIDGET_STATE_SCROLLING = "scrolling"; + field public static final String WIDGET_STATE_SWIPING = "swiping"; + field public static final String WIDGET_STATE_TAPPING = "tapping"; + field public static final String WIDGET_STATE_UNSPECIFIED = "unspecified"; + field public static final String WIDGET_STATE_ZOOMING = "zooming"; + } + + @FlaggedApi("android.app.jank.detailed_app_jank_metrics_api") public class RelativeFrameTimeHistogram { + ctor public RelativeFrameTimeHistogram(); + method public void addRelativeFrameTimeMillis(int); method @NonNull public int[] getBucketCounters(); method @NonNull public int[] getBucketEndpointsMillis(); } @@ -42521,7 +42521,7 @@ package android.service.settings.preferences { field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.GetValueRequest> CREATOR; } - public static final class GetValueRequest.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class GetValueRequest.Builder { ctor public GetValueRequest.Builder(@NonNull String, @NonNull String); method @NonNull public android.service.settings.preferences.GetValueRequest build(); } @@ -42542,7 +42542,7 @@ package android.service.settings.preferences { field public static final int RESULT_UNSUPPORTED = 1; // 0x1 } - public static final class GetValueResult.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class GetValueResult.Builder { ctor public GetValueResult.Builder(int); method @NonNull public android.service.settings.preferences.GetValueResult build(); method @NonNull public android.service.settings.preferences.GetValueResult.Builder setMetadata(@Nullable android.service.settings.preferences.SettingsPreferenceMetadata); @@ -42555,7 +42555,7 @@ package android.service.settings.preferences { field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.MetadataRequest> CREATOR; } - public static final class MetadataRequest.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class MetadataRequest.Builder { ctor public MetadataRequest.Builder(); method @NonNull public android.service.settings.preferences.MetadataRequest build(); } @@ -42571,7 +42571,7 @@ package android.service.settings.preferences { field public static final int RESULT_UNSUPPORTED = 1; // 0x1 } - public static final class MetadataResult.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class MetadataResult.Builder { ctor public MetadataResult.Builder(int); method @NonNull public android.service.settings.preferences.MetadataResult build(); method @NonNull public android.service.settings.preferences.MetadataResult.Builder setMetadataList(@NonNull java.util.List<android.service.settings.preferences.SettingsPreferenceMetadata>); @@ -42586,7 +42586,7 @@ package android.service.settings.preferences { field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.SetValueRequest> CREATOR; } - public static final class SetValueRequest.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SetValueRequest.Builder { ctor public SetValueRequest.Builder(@NonNull String, @NonNull String, @NonNull android.service.settings.preferences.SettingsPreferenceValue); method @NonNull public android.service.settings.preferences.SetValueRequest build(); } @@ -42608,14 +42608,13 @@ package android.service.settings.preferences { field public static final int RESULT_UNSUPPORTED = 1; // 0x1 } - public static final class SetValueResult.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SetValueResult.Builder { ctor public SetValueResult.Builder(int); method @NonNull public android.service.settings.preferences.SetValueResult build(); } @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SettingsPreferenceMetadata implements android.os.Parcelable { method public int describeContents(); - method @NonNull public java.util.List<java.lang.String> getBreadcrumbs(); method @NonNull public android.os.Bundle getExtras(); method @NonNull public String getKey(); method @Nullable public android.content.Intent getLaunchIntent(); @@ -42631,17 +42630,16 @@ package android.service.settings.preferences { method public boolean isWritable(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.preferences.SettingsPreferenceMetadata> CREATOR; + field public static final int DEEPLINK_ONLY = 2; // 0x2 field public static final int EXPECT_POST_CONFIRMATION = 1; // 0x1 - field public static final int EXPECT_PRE_CONFIRMATION = 2; // 0x2 field public static final int NO_DIRECT_ACCESS = 3; // 0x3 field public static final int NO_SENSITIVITY = 0; // 0x0 } - public static final class SettingsPreferenceMetadata.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SettingsPreferenceMetadata.Builder { ctor public SettingsPreferenceMetadata.Builder(@NonNull String, @NonNull String); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata build(); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setAvailable(boolean); - method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setBreadcrumbs(@NonNull java.util.List<java.lang.String>); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setEnabled(boolean); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setExtras(@NonNull android.os.Bundle); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.content.Intent); @@ -42688,7 +42686,7 @@ package android.service.settings.preferences { field public static final int TYPE_STRING = 3; // 0x3 } - public static final class SettingsPreferenceValue.Builder { + @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final class SettingsPreferenceValue.Builder { ctor public SettingsPreferenceValue.Builder(int); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue build(); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setBooleanValue(boolean); @@ -53484,9 +53482,9 @@ package android.view { field public static final int CHANGE_FRAME_RATE_ALWAYS = 1; // 0x1 field public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR; + field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_AT_LEAST = 2; // 0x2 field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0 field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1 - field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; // 0x2 field public static final int ROTATION_0 = 0; // 0x0 field public static final int ROTATION_180 = 2; // 0x2 field public static final int ROTATION_270 = 3; // 0x3 @@ -57120,6 +57118,7 @@ package android.view.contentcapture { method public void close(); method @NonNull public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext); method public final void destroy(); + method @FlaggedApi("android.view.contentcapture.flags.ccapi_baklava_enabled") public void flush(); method @Nullable public final android.view.contentcapture.ContentCaptureContext getContentCaptureContext(); method @NonNull public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId(); method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6d24e4684e77..6c5ac8a2726d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -360,6 +360,7 @@ package android { field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES"; field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"; field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD"; + field @FlaggedApi("android.content.pm.uid_based_provider_lookup") public static final String RESOLVE_COMPONENT_FOR_UID = "android.permission.RESOLVE_COMPONENT_FOR_UID"; field public static final String RESTART_WIFI_SUBSYSTEM = "android.permission.RESTART_WIFI_SUBSYSTEM"; field @FlaggedApi("android.permission.flags.health_connect_backup_restore_permission_enabled") public static final String RESTORE_HEALTH_CONNECT_DATA_AND_SETTINGS = "android.permission.RESTORE_HEALTH_CONNECT_DATA_AND_SETTINGS"; field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS"; @@ -4241,6 +4242,7 @@ package android.content.pm { method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback); method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener); method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName); + method @FlaggedApi("android.content.pm.uid_based_provider_lookup") @Nullable @RequiresPermission(android.Manifest.permission.RESOLVE_COMPONENT_FOR_UID) public android.content.pm.ProviderInfo resolveContentProviderForUid(@NonNull String, @NonNull android.content.pm.PackageManager.ComponentInfoFlags, int); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String); method public void sendDeviceCustomizationReadyBroadcast(); @@ -5079,8 +5081,8 @@ package android.hardware.contexthub { } @FlaggedApi("android.chre.flags.offload_api") public class HubEndpoint { - method @Nullable public android.hardware.contexthub.IHubEndpointLifecycleCallback getLifecycleCallback(); - method @Nullable public android.hardware.contexthub.IHubEndpointMessageCallback getMessageCallback(); + method @Nullable public android.hardware.contexthub.HubEndpointLifecycleCallback getLifecycleCallback(); + method @Nullable public android.hardware.contexthub.HubEndpointMessageCallback getMessageCallback(); method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection(); method @Nullable public String getTag(); method public int getVersion(); @@ -5095,14 +5097,19 @@ package android.hardware.contexthub { public static final class HubEndpoint.Builder { ctor public HubEndpoint.Builder(@NonNull android.content.Context); method @NonNull public android.hardware.contexthub.HubEndpoint build(); - method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback); - method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback); - method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull android.hardware.contexthub.IHubEndpointMessageCallback); - method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointMessageCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull android.hardware.contexthub.HubEndpointLifecycleCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.HubEndpointLifecycleCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull android.hardware.contexthub.HubEndpointMessageCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.HubEndpointMessageCallback); method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setServiceInfoCollection(@NonNull java.util.Collection<android.hardware.contexthub.HubServiceInfo>); method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setTag(@NonNull String); } + @FlaggedApi("android.chre.flags.offload_api") public interface HubEndpointDiscoveryCallback { + method public void onEndpointsStarted(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>); + method public void onEndpointsStopped(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>, int); + } + @FlaggedApi("android.chre.flags.offload_api") public final class HubEndpointInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier getIdentifier(); @@ -5126,6 +5133,16 @@ package android.hardware.contexthub { method public long getHub(); } + @FlaggedApi("android.chre.flags.offload_api") public interface HubEndpointLifecycleCallback { + method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int); + method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable String); + method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession); + } + + @FlaggedApi("android.chre.flags.offload_api") public interface HubEndpointMessageCallback { + method public void onMessageReceived(@NonNull android.hardware.contexthub.HubEndpointSession, @NonNull android.hardware.contexthub.HubMessage); + } + @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable { method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void close(); method @Nullable public String getServiceDescriptor(); @@ -5174,21 +5191,6 @@ package android.hardware.contexthub { method @NonNull public android.hardware.contexthub.HubServiceInfo build(); } - @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointDiscoveryCallback { - method public void onEndpointsStarted(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>); - method public void onEndpointsStopped(@NonNull java.util.List<android.hardware.contexthub.HubDiscoveryInfo>, int); - } - - @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback { - method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int); - method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable String); - method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession); - } - - @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback { - method public void onMessageReceived(@NonNull android.hardware.contexthub.HubEndpointSession, @NonNull android.hardware.contexthub.HubMessage); - } - } package android.hardware.devicestate { @@ -6192,16 +6194,16 @@ package android.hardware.location { method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler); method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.HubEndpointDiscoveryCallback, long); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.HubEndpointDiscoveryCallback, long); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.HubEndpointDiscoveryCallback, @NonNull String); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.HubEndpointDiscoveryCallback, @NonNull String); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.HubEndpointDiscoveryCallback); field public static final int AUTHORIZATION_DENIED = 0; // 0x0 field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1 field public static final int AUTHORIZATION_GRANTED = 2; // 0x2 @@ -12676,27 +12678,21 @@ package android.security { package android.security.advancedprotection { @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionFeature implements android.os.Parcelable { - ctor public AdvancedProtectionFeature(@NonNull String); + ctor public AdvancedProtectionFeature(int); method public int describeContents(); - method @NonNull public String getId(); + method public int getId(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.advancedprotection.AdvancedProtectionFeature> CREATOR; } @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager { - method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures(); method @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean); - field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG"; - field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE"; - field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE"; - field public static final String FEATURE_ID_DISALLOW_CELLULAR_2G = "android.security.advancedprotection.feature_disallow_2g"; - field public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = "android.security.advancedprotection.feature_disallow_install_unknown_sources"; - field public static final String FEATURE_ID_DISALLOW_USB = "android.security.advancedprotection.feature_disallow_usb"; - field public static final String FEATURE_ID_DISALLOW_WEP = "android.security.advancedprotection.feature_disallow_wep"; - field public static final String FEATURE_ID_ENABLE_MTE = "android.security.advancedprotection.feature_enable_mte"; - field public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = "android.security.advancedprotection.type_blocked_interaction"; - field public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING = "android.security.advancedprotection.type_disabled_setting"; + field public static final int FEATURE_ID_DISALLOW_CELLULAR_2G = 0; // 0x0 + field public static final int FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = 1; // 0x1 + field public static final int FEATURE_ID_DISALLOW_USB = 2; // 0x2 + field public static final int FEATURE_ID_DISALLOW_WEP = 3; // 0x3 + field public static final int FEATURE_ID_ENABLE_MTE = 4; // 0x4 } } @@ -19091,6 +19087,7 @@ package android.view.contentcapture { method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR; field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6 + field @FlaggedApi("android.view.contentcapture.flags.ccapi_baklava_enabled") public static final int TYPE_SESSION_FLUSH = 11; // 0xb field public static final int TYPE_SESSION_PAUSED = 8; // 0x8 field public static final int TYPE_SESSION_RESUMED = 7; // 0x7 field public static final int TYPE_VIEW_APPEARED = 1; // 0x1 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index fee8cdb1ce51..c3ef104075f2 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5834,7 +5834,11 @@ public class Activity extends ContextThemeWrapper final int size = permissions.length; int[] results = new int[size]; for (int i = 0; i < size; i++) { - results[i] = deviceContext.getPermissionRequestState(permissions[i]); + if (permissions[i] == null) { + results[i] = Context.PERMISSION_REQUEST_STATE_UNREQUESTABLE; + } else { + results[i] = deviceContext.getPermissionRequestState(permissions[i]); + } } return results; } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index abdfb53537f8..999db18a1229 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -485,6 +485,11 @@ public abstract class ActivityManagerInternal { */ public static final int OOM_ADJ_REASON_FOLLOW_UP = 23; + /** + * Oom Adj Reason: Update after oom adjuster configuration has changed. + */ + public static final int OOM_ADJ_REASON_RECONFIGURATION = 24; + @IntDef(prefix = {"OOM_ADJ_REASON_"}, value = { OOM_ADJ_REASON_NONE, OOM_ADJ_REASON_ACTIVITY, @@ -510,6 +515,7 @@ public abstract class ActivityManagerInternal { OOM_ADJ_REASON_RESTRICTION_CHANGE, OOM_ADJ_REASON_COMPONENT_DISABLED, OOM_ADJ_REASON_FOLLOW_UP, + OOM_ADJ_REASON_RECONFIGURATION, }) @Retention(RetentionPolicy.SOURCE) public @interface OomAdjReason {} diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java index 61b56877589b..599f1a8be233 100644 --- a/core/java/android/app/AppCompatTaskInfo.java +++ b/core/java/android/app/AppCompatTaskInfo.java @@ -27,6 +27,7 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Objects; /** * Stores App Compat information about a particular Task. @@ -58,16 +59,11 @@ public class AppCompatTaskInfo implements Parcelable { public int topActivityLetterboxHeight = PROPERTY_VALUE_UNSET; /** - * Contains the current app height of the letterboxed activity if available or - * {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise. + * Contains the app bounds of the top activity or size compat mode + * bounds when in size compat mode. If null, contains bounds. */ - public int topActivityLetterboxAppHeight = PROPERTY_VALUE_UNSET; - - /** - * Contains the current app width of the letterboxed activity if available or - * {@link TaskInfo#PROPERTY_VALUE_UNSET} otherwise. - */ - public int topActivityLetterboxAppWidth = PROPERTY_VALUE_UNSET; + @NonNull + public final Rect topActivityAppBounds = new Rect(); /** * Contains the top activity bounds when the activity is letterboxed. @@ -350,8 +346,7 @@ public class AppCompatTaskInfo implements Parcelable { && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition && topActivityLetterboxWidth == that.topActivityLetterboxWidth && topActivityLetterboxHeight == that.topActivityLetterboxHeight - && topActivityLetterboxAppWidth == that.topActivityLetterboxAppWidth - && topActivityLetterboxAppHeight == that.topActivityLetterboxAppHeight + && topActivityAppBounds.equals(that.topActivityAppBounds) && topActivityLetterboxHorizontalPosition == that.topActivityLetterboxHorizontalPosition && cameraCompatTaskInfo.equalsForTaskOrganizer(that.cameraCompatTaskInfo); @@ -371,8 +366,7 @@ public class AppCompatTaskInfo implements Parcelable { == that.topActivityLetterboxHorizontalPosition && topActivityLetterboxWidth == that.topActivityLetterboxWidth && topActivityLetterboxHeight == that.topActivityLetterboxHeight - && topActivityLetterboxAppWidth == that.topActivityLetterboxAppWidth - && topActivityLetterboxAppHeight == that.topActivityLetterboxAppHeight + && topActivityAppBounds.equals(that.topActivityAppBounds) && cameraCompatTaskInfo.equalsForCompatUi(that.cameraCompatTaskInfo); } @@ -385,8 +379,7 @@ public class AppCompatTaskInfo implements Parcelable { topActivityLetterboxHorizontalPosition = source.readInt(); topActivityLetterboxWidth = source.readInt(); topActivityLetterboxHeight = source.readInt(); - topActivityLetterboxAppWidth = source.readInt(); - topActivityLetterboxAppHeight = source.readInt(); + topActivityAppBounds.set(Objects.requireNonNull(source.readTypedObject(Rect.CREATOR))); topActivityLetterboxBounds = source.readTypedObject(Rect.CREATOR); cameraCompatTaskInfo = source.readTypedObject(CameraCompatTaskInfo.CREATOR); } @@ -401,8 +394,7 @@ public class AppCompatTaskInfo implements Parcelable { dest.writeInt(topActivityLetterboxHorizontalPosition); dest.writeInt(topActivityLetterboxWidth); dest.writeInt(topActivityLetterboxHeight); - dest.writeInt(topActivityLetterboxAppWidth); - dest.writeInt(topActivityLetterboxAppHeight); + dest.writeTypedObject(topActivityAppBounds, flags); dest.writeTypedObject(topActivityLetterboxBounds, flags); dest.writeTypedObject(cameraCompatTaskInfo, flags); } @@ -421,8 +413,7 @@ public class AppCompatTaskInfo implements Parcelable { + topActivityLetterboxHorizontalPosition + " topActivityLetterboxWidth=" + topActivityLetterboxWidth + " topActivityLetterboxHeight=" + topActivityLetterboxHeight - + " topActivityLetterboxAppWidth=" + topActivityLetterboxAppWidth - + " topActivityLetterboxAppHeight=" + topActivityLetterboxAppHeight + + " topActivityAppBounds=" + topActivityAppBounds + " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled() + " isSystemFullscreenOverrideEnabled=" + isSystemFullscreenOverrideEnabled() + " hasMinAspectRatioOverride=" + hasMinAspectRatioOverride() diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl index b4dee2e937cb..56ed290baf2e 100644 --- a/core/java/android/app/AppOpsManager.aidl +++ b/core/java/android/app/AppOpsManager.aidl @@ -19,6 +19,7 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEvent; +parcelable AppOpsManager.NotedOp; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpEntry; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 19138126698c..53b4b54e9f93 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -262,6 +262,23 @@ public class AppOpsManager { private static final Object sLock = new Object(); + // A map that records noted times for each op. + private static ArrayMap<NotedOp, Integer> sPendingNotedOps = new ArrayMap<>(); + private static HandlerThread sHandlerThread; + private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000; + + private boolean isNoteOpBatchingSupported() { + // If noteOp is called from system server no IPC is made, hence we don't need batching. + if (Process.myUid() == Process.SYSTEM_UID) { + return false; + } + return Flags.noteOpBatchingEnabled(); + } + + private static final Object sBatchedNoteOpLock = new Object(); + @GuardedBy("sBatchedNoteOpLock") + private static boolean sIsBatchedNoteOpCallScheduled = false; + /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ @GuardedBy("sLock") private static @Nullable OnOpNotedCallback sOnOpNotedCallback; @@ -7466,6 +7483,141 @@ public class AppOpsManager { } /** + * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch + * + * @hide + */ + public static final class NotedOp implements Parcelable { + private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp; + private final @IntRange(from = 0) int mUid; + private final @Nullable String mPackageName; + private final @Nullable String mAttributionTag; + private final int mVirtualDeviceId; + private final @Nullable String mMessage; + private final boolean mShouldCollectAsyncNotedOp; + private final boolean mShouldCollectMessage; + + public NotedOp(int op, int uid, @Nullable String packageName, + @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, + boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) { + mOp = op; + mUid = uid; + mPackageName = packageName; + mAttributionTag = attributionTag; + mVirtualDeviceId = virtualDeviceId; + mMessage = message; + mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp; + mShouldCollectMessage = shouldCollectMessage; + } + + NotedOp(Parcel source) { + mOp = source.readInt(); + mUid = source.readInt(); + mPackageName = source.readString(); + mAttributionTag = source.readString(); + mVirtualDeviceId = source.readInt(); + mMessage = source.readString(); + mShouldCollectAsyncNotedOp = source.readBoolean(); + mShouldCollectMessage = source.readBoolean(); + } + + public int getOp() { + return mOp; + } + + public int getUid() { + return mUid; + } + + public @Nullable String getPackageName() { + return mPackageName; + } + + public @Nullable String getAttributionTag() { + return mAttributionTag; + } + + public int getVirtualDeviceId() { + return mVirtualDeviceId; + } + + public @Nullable String getMessage() { + return mMessage; + } + + public boolean getShouldCollectAsyncNotedOp() { + return mShouldCollectAsyncNotedOp; + } + + public boolean getShouldCollectMessage() { + return mShouldCollectMessage; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mOp); + dest.writeInt(mUid); + dest.writeString(mPackageName); + dest.writeString(mAttributionTag); + dest.writeInt(mVirtualDeviceId); + dest.writeString(mMessage); + dest.writeBoolean(mShouldCollectAsyncNotedOp); + dest.writeBoolean(mShouldCollectMessage); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NotedOp that = (NotedOp) o; + return mOp == that.mOp + && mUid == that.mUid + && Objects.equals(mPackageName, that.mPackageName) + && Objects.equals(mAttributionTag, that.mAttributionTag) + && mVirtualDeviceId == that.mVirtualDeviceId + && Objects.equals(mMessage, that.mMessage) + && Objects.equals(mShouldCollectAsyncNotedOp, that.mShouldCollectAsyncNotedOp) + && Objects.equals(mShouldCollectMessage, that.mShouldCollectMessage); + } + + @Override + public int hashCode() { + return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId, + mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage); + } + + @Override + public String toString() { + return "NotedOp{" + + "mOp=" + mOp + + ", mUid=" + mUid + + ", mPackageName=" + mPackageName + + ", mAttributionTag=" + mAttributionTag + + ", mVirtualDeviceId=" + mVirtualDeviceId + + ", mMessage=" + mMessage + + ", mShouldCollectAsyncNotedOp=" + mShouldCollectAsyncNotedOp + + ", mShouldCollectMessage=" + mShouldCollectMessage + + "}"; + } + + public static final @NonNull Creator<NotedOp> CREATOR = + new Creator<>() { + @Override public NotedOp createFromParcel(Parcel source) { + return new NotedOp(source); + } + + @Override public NotedOp[] newArray(int size) { + return new NotedOp[size]; + } + }; + } + + /** * Computes the sum of the counts for the given flags in between the begin and * end UID states. * @@ -9301,6 +9453,65 @@ public class AppOpsManager { message); } + /** + * Create a new NotedOp object to represent the note operation. If the note operation is + * a duplicate in the buffer, put it in a batch for an async binder call to the system server. + * + * @return whether this note operation is a duplicate in the buffer. If it's the + * first, the noteOp is not batched, the caller should manually call noteOperation. + */ + private boolean batchDuplicateNoteOps(int op, int uid, @Nullable String packageName, + @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, + boolean collectAsync, boolean shouldCollectMessage) { + synchronized (sBatchedNoteOpLock) { + NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag, + virtualDeviceId, message, collectAsync, shouldCollectMessage); + + // Batch same noteOp calls and send them with their counters to the system + // service asynchronously. The time window for batching is specified in + // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go + // through binder API. Accumulate subsequent same noteOp calls during the + // time window in sPendingNotedOps. + boolean isDuplicated = sPendingNotedOps.containsKey(notedOp); + if (!isDuplicated) { + sPendingNotedOps.put(notedOp, 0); + } else { + sPendingNotedOps.merge(notedOp, 1, Integer::sum); + } + + if (!sIsBatchedNoteOpCallScheduled) { + if (sHandlerThread == null) { + sHandlerThread = new HandlerThread("AppOpsManagerNoteOpBatching"); + sHandlerThread.start(); + } + + sHandlerThread.getThreadHandler().postDelayed(() -> { + ArrayMap<NotedOp, Integer> pendingNotedOpsCopy; + synchronized(sBatchedNoteOpLock) { + sIsBatchedNoteOpCallScheduled = false; + pendingNotedOpsCopy = sPendingNotedOps; + sPendingNotedOps = new ArrayMap<>(); + } + for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) { + if (pendingNotedOpsCopy.valueAt(i) == 0) { + pendingNotedOpsCopy.removeAt(i); + } + } + if (!pendingNotedOpsCopy.isEmpty()) { + try { + mService.noteOperationsInBatch(pendingNotedOpsCopy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + }, NOTE_OP_BATCHING_DELAY_MILLIS); + + sIsBatchedNoteOpCallScheduled = true; + } + return isDuplicated; + } + } + private int noteOpNoThrow(int op, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, @Nullable String message) { try { @@ -9315,15 +9526,34 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp; - if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { - syncOp = mService.noteOperation(op, uid, packageName, attributionTag, - collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); - } else { - syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, - virtualDeviceId, collectionMode == COLLECT_ASYNC, message, - shouldCollectMessage); + SyncNotedAppOp syncOp = null; + boolean isNoteOpDuplicated = false; + if (isNoteOpBatchingSupported()) { + int mode = sAppOpModeCache.query( + new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, + "noteOpNoThrow")); + // For FOREGROUND mode, we still need to make a binder call to the system service + // to translate it to ALLOWED or IGNORED. So no batching is needed. + if (mode != MODE_FOREGROUND) { + isNoteOpDuplicated = batchDuplicateNoteOps(op, uid, packageName, attributionTag, + virtualDeviceId, message, + collectionMode == COLLECT_ASYNC, shouldCollectMessage); + + syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName); + } + } + + if (!isNoteOpDuplicated) { + if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { + syncOp = mService.noteOperation(op, uid, packageName, attributionTag, + collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); + } else { + syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, + virtualDeviceId, collectionMode == COLLECT_ASYNC, message, + shouldCollectMessage); + } } + if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { collectNotedOpForSelf(syncOp); diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index b21defbcc0e3..8b7ea0f8b46a 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.OctFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; @@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal { */ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, - @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, SyncNotedAppOp> superImpl); + @Nullable String message, boolean shouldCollectMessage, int notedCount, + @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, Integer, SyncNotedAppOp> superImpl); /** * Allows overriding note proxy operation behavior. diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index da338474a448..2dead565fa85 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1751,6 +1751,19 @@ public class ApplicationPackageManager extends PackageManager { } } + /** @hide **/ + @Override + public ProviderInfo resolveContentProviderForUid(@NonNull String authority, + ComponentInfoFlags flags, int callingUid) { + try { + return mPM.resolveContentProviderForUid(authority, + updateFlagsForComponent(flags.getValue(), getUserId(), null), getUserId(), + callingUid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override public List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) { return queryContentProviders(processName, uid, ComponentInfoFlags.of(flags)); diff --git a/core/java/android/app/BackgroundStartPrivileges.java b/core/java/android/app/BackgroundStartPrivileges.java index 20278eaee3b2..adea0a8a0702 100644 --- a/core/java/android/app/BackgroundStartPrivileges.java +++ b/core/java/android/app/BackgroundStartPrivileges.java @@ -23,12 +23,13 @@ import android.os.IBinder; import com.android.internal.util.Preconditions; import java.util.List; +import java.util.Objects; /** * Privileges granted to a Process that allows it to execute starts from the background. * @hide */ -public class BackgroundStartPrivileges { +public final class BackgroundStartPrivileges { /** No privileges. */ public static final BackgroundStartPrivileges NONE = new BackgroundStartPrivileges( false, false, null); @@ -190,4 +191,22 @@ public class BackgroundStartPrivileges { + ", originatingToken=" + mOriginatingToken + ']'; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BackgroundStartPrivileges that = (BackgroundStartPrivileges) o; + return mAllowsBackgroundActivityStarts == that.mAllowsBackgroundActivityStarts + && mAllowsBackgroundForegroundServiceStarts + == that.mAllowsBackgroundForegroundServiceStarts + && Objects.equals(mOriginatingToken, that.mOriginatingToken); + } + + @Override + public int hashCode() { + return Objects.hash(mAllowsBackgroundActivityStarts, + mAllowsBackgroundForegroundServiceStarts, + mOriginatingToken); + } } diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl index 1ff7a17e578f..d71ee7c712e7 100644 --- a/core/java/android/app/IUserSwitchObserver.aidl +++ b/core/java/android/app/IUserSwitchObserver.aidl @@ -19,10 +19,10 @@ package android.app; import android.os.IRemoteCallback; /** {@hide} */ -interface IUserSwitchObserver { - void onBeforeUserSwitching(int newUserId); - oneway void onUserSwitching(int newUserId, IRemoteCallback reply); - oneway void onUserSwitchComplete(int newUserId); - oneway void onForegroundProfileSwitch(int newProfileId); - oneway void onLockedBootComplete(int newUserId); +oneway interface IUserSwitchObserver { + void onBeforeUserSwitching(int newUserId, IRemoteCallback reply); + void onUserSwitching(int newUserId, IRemoteCallback reply); + void onUserSwitchComplete(int newUserId); + void onForegroundProfileSwitch(int newProfileId); + void onLockedBootComplete(int newUserId); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 17638ee76dba..eeb1ebb69b03 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -11208,8 +11208,8 @@ public class Notification implements Parcelable private static final String KEY_SEGMENT_LENGTH = "length"; private static final String KEY_POINT_POSITION = "position"; - private static final int MAX_PROGRESS_SEGMENT_LIMIT = 15; - private static final int MAX_PROGRESS_STOP_LIMIT = 5; + private static final int MAX_PROGRESS_SEGMENT_LIMIT = 10; + private static final int MAX_PROGRESS_POINT_LIMIT = 4; private static final int DEFAULT_PROGRESS_MAX = 100; private List<Segment> mProgressSegments = new ArrayList<>(); @@ -11286,7 +11286,9 @@ public class Notification implements Parcelable mProgressSegments = new ArrayList<>(); } mProgressSegments.clear(); - mProgressSegments.addAll(progressSegments); + for (Segment segment : progressSegments) { + addProgressSegment(segment); + } return this; } @@ -11302,7 +11304,11 @@ public class Notification implements Parcelable if (mProgressSegments == null) { mProgressSegments = new ArrayList<>(); } - mProgressSegments.add(segment); + if (segment.getLength() > 0) { + mProgressSegments.add(segment); + } else { + Log.w(TAG, "Dropped the segment. The length is not a positive integer."); + } return this; } @@ -11327,7 +11333,14 @@ public class Notification implements Parcelable * @see Point */ public @NonNull ProgressStyle setProgressPoints(@NonNull List<Point> points) { - mProgressPoints = new ArrayList<>(points); + if (mProgressPoints == null) { + mProgressPoints = new ArrayList<>(); + } + mProgressPoints.clear(); + + for (Point point: points) { + addProgressPoint(point); + } return this; } @@ -11348,7 +11361,17 @@ public class Notification implements Parcelable if (mProgressPoints == null) { mProgressPoints = new ArrayList<>(); } - mProgressPoints.add(point); + if (point.getPosition() >= 0) { + mProgressPoints.add(point); + + if (mProgressPoints.size() > MAX_PROGRESS_POINT_LIMIT) { + Log.w(TAG, "Progress points limit is reached. First" + + MAX_PROGRESS_POINT_LIMIT + " points will be rendered."); + } + + } else { + Log.w(TAG, "Dropped the point. The position is a negative integer."); + } return this; } @@ -11384,8 +11407,7 @@ public class Notification implements Parcelable } else { int progressMax = 0; int validSegmentCount = 0; - for (int i = 0; i < progressSegment.size() - && validSegmentCount < MAX_PROGRESS_SEGMENT_LIMIT; i++) { + for (int i = 0; i < progressSegment.size(); i++) { int segmentLength = progressSegment.get(i).getLength(); if (segmentLength > 0) { try { @@ -11832,6 +11854,30 @@ public class Notification implements Parcelable totalLength = DEFAULT_PROGRESS_MAX; segments.add(sanitizeSegment(new Segment(totalLength), backgroundColor, defaultProgressColor)); + } else if (segments.size() > MAX_PROGRESS_SEGMENT_LIMIT) { + // If segment limit is exceeded. All segments will be replaced + // with a single segment + boolean allSameColor = true; + int firstSegmentColor = segments.get(0).getColor(); + + for (int i = 1; i < segments.size(); i++) { + if (segments.get(i).getColor() != firstSegmentColor) { + allSameColor = false; + break; + } + } + + // This single segment length has same max as total. + final Segment singleSegment = new Segment(totalLength); + // Single segment color: if all segments have the same color, + // use that color. Otherwise, use 0 / default. + singleSegment.setColor(allSameColor ? firstSegmentColor + : Notification.COLOR_DEFAULT); + + segments.clear(); + segments.add(sanitizeSegment(singleSegment, + backgroundColor, + defaultProgressColor)); } // Ensure point color contrasts. @@ -11840,6 +11886,9 @@ public class Notification implements Parcelable final int position = point.getPosition(); if (position < 0 || position > totalLength) continue; points.add(sanitizePoint(point, backgroundColor, defaultProgressColor)); + if (points.size() == MAX_PROGRESS_POINT_LIMIT) { + break; + } } model = new NotificationProgressModel(segments, points, @@ -11868,8 +11917,10 @@ public class Notification implements Parcelable * has the same hue as the original color, but is lightened or darkened depending on * whether the background is dark or light. * + * @hide */ - private int sanitizeProgressColor(@ColorInt int color, + @VisibleForTesting + public static int sanitizeProgressColor(@ColorInt int color, @ColorInt int bg, @ColorInt int defaultColor) { return Builder.ensureColorContrast( diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 8ed66eb7e6c0..e9b889a2f1aa 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -55,6 +55,7 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; +import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; @@ -677,9 +678,14 @@ public class NotificationManager { } /** {@hide} */ - @UnsupportedAppUsage - public NotificationManager(Context context, InstantSource clock) + public NotificationManager(Context context) { + this(context, SystemClock.elapsedRealtimeClock()); + } + + /** {@hide} */ + @UnsupportedAppUsage + public NotificationManager(Context context, InstantSource clock) { mContext = context; mClock = clock; } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 920b19cd8f78..0bbe9434293a 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -17,7 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; -import static android.provider.flags.Flags.stageFlagsForBuild; +import static android.provider.flags.Flags.newStoragePublicApi; import static android.server.Flags.removeGameManagerServiceFromWear; import android.accounts.AccountManager; @@ -289,7 +289,6 @@ import com.android.internal.os.IDropBoxManagerService; import com.android.internal.policy.PhoneLayoutInflater; import com.android.internal.util.Preconditions; -import java.time.InstantSource; import java.util.Map; import java.util.Objects; @@ -625,8 +624,8 @@ public final class SystemServiceRegistry { com.android.internal.R.style.Theme_Dialog, com.android.internal.R.style.Theme_Holo_Dialog, com.android.internal.R.style.Theme_DeviceDefault_Dialog, - com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)), - InstantSource.system()); + com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)) + ); }}); registerService(Context.PEOPLE_SERVICE, PeopleManager.class, @@ -1841,7 +1840,7 @@ public final class SystemServiceRegistry { VirtualizationFrameworkInitializer.registerServiceWrappers(); ConnectivityFrameworkInitializerBaklava.registerServiceWrappers(); - if (stageFlagsForBuild()) { + if (newStoragePublicApi()) { ConfigInfrastructureFrameworkInitializer.registerServiceWrappers(); } diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java index 727799a1f948..1664cfb6f7a8 100644 --- a/core/java/android/app/UserSwitchObserver.java +++ b/core/java/android/app/UserSwitchObserver.java @@ -30,7 +30,11 @@ public class UserSwitchObserver extends IUserSwitchObserver.Stub { } @Override - public void onBeforeUserSwitching(int newUserId) throws RemoteException {} + public void onBeforeUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException { + if (reply != null) { + reply.sendResult(null); + } + } @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException { diff --git a/core/java/android/app/contextualsearch/ContextualSearchManager.java b/core/java/android/app/contextualsearch/ContextualSearchManager.java index 3438cc861661..ad43f271a910 100644 --- a/core/java/android/app/contextualsearch/ContextualSearchManager.java +++ b/core/java/android/app/contextualsearch/ContextualSearchManager.java @@ -48,7 +48,9 @@ public final class ContextualSearchManager { /** * Key to get the entrypoint from the extras of the activity launched by contextual search. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_ENTRYPOINT = "android.app.contextualsearch.extra.ENTRYPOINT"; @@ -56,14 +58,18 @@ public final class ContextualSearchManager { /** * Key to get the flag_secure value from the extras of the activity launched by contextual * search. The value will be true if flag_secure is found in any of the visible activities. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_FLAG_SECURE_FOUND = "android.app.contextualsearch.extra.FLAG_SECURE_FOUND"; /** * Key to get the screenshot from the extras of the activity launched by contextual search. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_SCREENSHOT = "android.app.contextualsearch.extra.SCREENSHOT"; @@ -71,7 +77,9 @@ public final class ContextualSearchManager { /** * Key to check whether managed profile is visible from the extras of the activity launched by * contextual search. The value will be true if any one of the visible apps is managed. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_IS_MANAGED_PROFILE_VISIBLE = "android.app.contextualsearch.extra.IS_MANAGED_PROFILE_VISIBLE"; @@ -79,7 +87,9 @@ public final class ContextualSearchManager { /** * Key to get the list of visible packages from the extras of the activity launched by * contextual search. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_VISIBLE_PACKAGE_NAMES = "android.app.contextualsearch.extra.VISIBLE_PACKAGE_NAMES"; @@ -87,7 +97,9 @@ public final class ContextualSearchManager { /** * Key to get the time the user made the invocation request, based on * {@link SystemClock#uptimeMillis()}. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH * * TODO: un-hide in W * @@ -99,11 +111,24 @@ public final class ContextualSearchManager { /** * Key to get the binder token from the extras of the activity launched by contextual search. * This token is needed to invoke {@link CallbackToken#getContextualSearchState} method. - * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH */ public static final String EXTRA_TOKEN = "android.app.contextualsearch.extra.TOKEN"; /** + * Key to check whether audio is playing when contextual search is invoked. + * Only supposed to be used with ACTION_LAUNCH_CONTEXTUAL_SEARCH. + * + * @see #ACTION_LAUNCH_CONTEXTUAL_SEARCH + * + * @hide + */ + public static final String EXTRA_IS_AUDIO_PLAYING = + "android.app.contextualsearch.extra.IS_AUDIO_PLAYING"; + + /** * Intent action for contextual search invocation. The app providing the contextual search * experience must add this intent filter action to the activity it wants to be launched. * <br> diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig index e8cfd79c9cc7..c19921dcdc61 100644 --- a/core/java/android/app/contextualsearch/flags.aconfig +++ b/core/java/android/app/contextualsearch/flags.aconfig @@ -8,6 +8,7 @@ flag { bug: "309689654" is_exported: true } + flag { name: "enable_token_refresh" namespace: "machine_learning" @@ -27,4 +28,11 @@ flag { namespace: "sysui_integrations" description: "Identify live contextual search UI to exclude from contextual search screenshot." bug: "372510690" +} + +flag { + name: "include_audio_playing_status" + namespace: "sysui_integrations" + description: "Add audio playing status to the contextual search invocation intent." + bug: "372935419" }
\ No newline at end of file diff --git a/core/java/android/app/jank/AppJankStats.java b/core/java/android/app/jank/AppJankStats.java index eea1d2ba5b9e..6ef6a44ddfbb 100644 --- a/core/java/android/app/jank/AppJankStats.java +++ b/core/java/android/app/jank/AppJankStats.java @@ -41,7 +41,8 @@ public final class AppJankStats { // The id that has been set for the widget. private String mWidgetId; - // A general category that the widget applies to. + // A general category the widget falls into based on the functions it performs or helps + // facilitate. private String mWidgetCategory; // The states that the UI elements can report @@ -53,78 +54,78 @@ public final class AppJankStats { // Total number of frames determined to be janky during the reported state. private long mJankyFrames; - // Histogram of frame duration overruns encoded in predetermined buckets. - private FrameOverrunHistogram mFrameOverrunHistogram; + // Histogram of relative frame times encoded in predetermined buckets. + private RelativeFrameTimeHistogram mRelativeFrameTimeHistogram; /** Used to indicate no widget category has been set. */ - public static final String WIDGET_CATEGORY_UNSPECIFIED = - "widget_category_unspecified"; + public static final String WIDGET_CATEGORY_UNSPECIFIED = "unspecified"; /** UI elements that facilitate scrolling. */ - public static final String SCROLL = "scroll"; + public static final String WIDGET_CATEGORY_SCROLL = "scroll"; /** UI elements that facilitate playing animations. */ - public static final String ANIMATION = "animation"; + public static final String WIDGET_CATEGORY_ANIMATION = "animation"; /** UI elements that facilitate media playback. */ - public static final String MEDIA = "media"; + public static final String WIDGET_CATEGORY_MEDIA = "media"; /** UI elements that facilitate in-app navigation. */ - public static final String NAVIGATION = "navigation"; + public static final String WIDGET_CATEGORY_NAVIGATION = "navigation"; /** UI elements that facilitate displaying, hiding or interacting with keyboard. */ - public static final String KEYBOARD = "keyboard"; - - /** UI elements that facilitate predictive back gesture navigation. */ - public static final String PREDICTIVE_BACK = "predictive_back"; + public static final String WIDGET_CATEGORY_KEYBOARD = "keyboard"; /** UI elements that don't fall in one or any of the other categories. */ - public static final String OTHER = "other"; + public static final String WIDGET_CATEGORY_OTHER = "other"; /** Used to indicate no widget state has been set. */ - public static final String WIDGET_STATE_UNSPECIFIED = "widget_state_unspecified"; + public static final String WIDGET_STATE_UNSPECIFIED = "unspecified"; /** Used to indicate the UI element currently has no state and is idle. */ - public static final String NONE = "none"; + public static final String WIDGET_STATE_NONE = "none"; /** Used to indicate the UI element is currently scrolling. */ - public static final String SCROLLING = "scrolling"; + public static final String WIDGET_STATE_SCROLLING = "scrolling"; /** Used to indicate the UI element is currently being flung. */ - public static final String FLINGING = "flinging"; + public static final String WIDGET_STATE_FLINGING = "flinging"; /** Used to indicate the UI element is currently being swiped. */ - public static final String SWIPING = "swiping"; + public static final String WIDGET_STATE_SWIPING = "swiping"; /** Used to indicate the UI element is currently being dragged. */ - public static final String DRAGGING = "dragging"; + public static final String WIDGET_STATE_DRAGGING = "dragging"; /** Used to indicate the UI element is currently zooming. */ - public static final String ZOOMING = "zooming"; + public static final String WIDGET_STATE_ZOOMING = "zooming"; /** Used to indicate the UI element is currently animating. */ - public static final String ANIMATING = "animating"; + public static final String WIDGET_STATE_ANIMATING = "animating"; /** Used to indicate the UI element is currently playing media. */ - public static final String PLAYBACK = "playback"; + public static final String WIDGET_STATE_PLAYBACK = "playback"; /** Used to indicate the UI element is currently being tapped on, for example on a keyboard. */ - public static final String TAPPING = "tapping"; + public static final String WIDGET_STATE_TAPPING = "tapping"; + + /** Used to indicate predictive back navigation is currently being used */ + public static final String WIDGET_STATE_PREDICTIVE_BACK = "predictive_back"; /** + * Provide an organized way to group widgets that have similar purposes or perform related + * functions. * @hide */ - @StringDef(value = { + @StringDef(prefix = {"WIDGET_CATEGORY_"}, value = { WIDGET_CATEGORY_UNSPECIFIED, - SCROLL, - ANIMATION, - MEDIA, - NAVIGATION, - KEYBOARD, - PREDICTIVE_BACK, - OTHER + WIDGET_CATEGORY_SCROLL, + WIDGET_CATEGORY_ANIMATION, + WIDGET_CATEGORY_MEDIA, + WIDGET_CATEGORY_NAVIGATION, + WIDGET_CATEGORY_KEYBOARD, + WIDGET_CATEGORY_OTHER }) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @Retention(RetentionPolicy.SOURCE) @@ -133,17 +134,18 @@ public final class AppJankStats { /** * @hide */ - @StringDef(value = { + @StringDef(prefix = {"WIDGET_STATE_"}, value = { WIDGET_STATE_UNSPECIFIED, - NONE, - SCROLLING, - FLINGING, - SWIPING, - DRAGGING, - ZOOMING, - ANIMATING, - PLAYBACK, - TAPPING, + WIDGET_STATE_NONE, + WIDGET_STATE_SCROLLING, + WIDGET_STATE_FLINGING, + WIDGET_STATE_SWIPING, + WIDGET_STATE_DRAGGING, + WIDGET_STATE_ZOOMING, + WIDGET_STATE_ANIMATING, + WIDGET_STATE_PLAYBACK, + WIDGET_STATE_TAPPING, + WIDGET_STATE_PREDICTIVE_BACK }) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @Retention(RetentionPolicy.SOURCE) @@ -156,31 +158,33 @@ public final class AppJankStats { * * @param appUid the Uid of the App that is collecting jank stats. * @param widgetId the widget id that frames will be associated to. - * @param widgetCategory a general functionality category that the widget falls into. Must be - * one of the following: SCROLL, ANIMATION, MEDIA, NAVIGATION, KEYBOARD, - * PREDICTIVE_BACK, OTHER or will be set to WIDGET_CATEGORY_UNSPECIFIED - * if no value is passed. - * @param widgetState the state the widget was in while frames were counted. Must be one of - * the following: NONE, SCROLLING, FLINGING, SWIPING, DRAGGING, ZOOMING, - * ANIMATING, PLAYBACK, TAPPING or will be set to WIDGET_STATE_UNSPECIFIED - * if no value is passed. + * @param widgetCategory a category used to organize widgets in a structured way that indicates + * they serve a similar purpose or perform related functions. Must be + * prefixed with WIDGET_CATEGORY_ and have a suffix of one of the + * following:SCROLL, ANIMATION, MEDIA, NAVIGATION, KEYBOARD, OTHER or + * will be set to UNSPECIFIED if no value is passed. + * @param widgetState the state the widget was in while frames were counted. Must be prefixed + * with WIDGET_STATE_ and have a suffix of one of the following: + * NONE, SCROLLING, FLINGING, SWIPING, DRAGGING, ZOOMING, ANIMATING, + * PLAYBACK, TAPPING, PREDICTIVE_BACK or will be set to + * WIDGET_STATE_UNSPECIFIED if no value is passed. * @param totalFrames the total number of frames that were counted for this stat. * @param jankyFrames the total number of janky frames that were counted for this stat. - * @param frameOverrunHistogram the histogram with predefined buckets. See - * {@link #getFrameOverrunHistogram()} for details. + * @param relativeFrameTimeHistogram the histogram with predefined buckets. See + * {@link #getRelativeFrameTimeHistogram()} for details. * */ public AppJankStats(int appUid, @NonNull String widgetId, @Nullable @WidgetCategory String widgetCategory, @Nullable @WidgetState String widgetState, long totalFrames, long jankyFrames, - @NonNull FrameOverrunHistogram frameOverrunHistogram) { + @NonNull RelativeFrameTimeHistogram relativeFrameTimeHistogram) { mUid = appUid; mWidgetId = widgetId; mWidgetCategory = widgetCategory != null ? widgetCategory : WIDGET_CATEGORY_UNSPECIFIED; mWidgetState = widgetState != null ? widgetState : WIDGET_STATE_UNSPECIFIED; mTotalFrames = totalFrames; mJankyFrames = jankyFrames; - mFrameOverrunHistogram = frameOverrunHistogram; + mRelativeFrameTimeHistogram = relativeFrameTimeHistogram; } /** @@ -203,7 +207,7 @@ public final class AppJankStats { /** * Returns the category that the widget's functionality generally falls into, or - * widget_category_unspecified {@link #WIDGET_CATEGORY_UNSPECIFIED} if no value was passed in. + * {@link #WIDGET_CATEGORY_UNSPECIFIED} if no value was passed in. * * @return the category that the widget's functionality generally falls into, this value cannot * be null. @@ -213,7 +217,7 @@ public final class AppJankStats { } /** - * Returns the widget's state that was reported for this stat, or widget_state_unspecified + * Returns the widget's state that was reported for this stat, or * {@link #WIDGET_STATE_UNSPECIFIED} if no value was passed in. * * @return the widget's state that was reported for this stat. This value cannot be null. @@ -241,13 +245,13 @@ public final class AppJankStats { } /** - * Returns a Histogram containing frame overrun times in millis grouped into predefined buckets. - * See {@link FrameOverrunHistogram} for more information. + * Returns a Histogram containing relative frame times in millis grouped into predefined + * buckets. See {@link RelativeFrameTimeHistogram} for more information. * - * @return Histogram containing frame overrun times in predefined buckets. This value cannot + * @return Histogram containing relative frame times in predefined buckets. This value cannot * be null. */ - public @NonNull FrameOverrunHistogram getFrameOverrunHistogram() { - return mFrameOverrunHistogram; + public @NonNull RelativeFrameTimeHistogram getRelativeFrameTimeHistogram() { + return mRelativeFrameTimeHistogram; } } diff --git a/core/java/android/app/jank/FrameOverrunHistogram.java b/core/java/android/app/jank/FrameOverrunHistogram.java deleted file mode 100644 index 3ad6531a46bf..000000000000 --- a/core/java/android/app/jank/FrameOverrunHistogram.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.jank; - -import android.annotation.FlaggedApi; -import android.annotation.NonNull; - -import java.util.Arrays; - -/** - * This class is intended to be used when reporting {@link AppJankStats} back to the system. It's - * intended to be used by library widgets to help facilitate the reporting of frame overrun times - * by adding those times into predefined buckets. - */ -@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) -public class FrameOverrunHistogram { - private static int[] sBucketEndpoints = new int[]{ - Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18, - -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, 30, 40, - 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000 - }; - private int[] mBucketCounts; - - /** - * Create a new instance of FrameOverrunHistogram. - */ - public FrameOverrunHistogram() { - mBucketCounts = new int[sBucketEndpoints.length]; - } - - /** - * Increases the count by one for the bucket representing the frame overrun duration. - * - * @param frameOverrunMillis frame overrun duration in millis, frame overrun is the difference - * between a frames deadline and when it was rendered. - */ - public void addFrameOverrunMillis(int frameOverrunMillis) { - int countsIndex = getIndexForCountsFromOverrunTime(frameOverrunMillis); - mBucketCounts[countsIndex]++; - } - - /** - * Returns the counts for the all the frame overrun buckets. - * - * @return an array of integers representing the counts of frame overrun times. This value - * cannot be null. - */ - public @NonNull int[] getBucketCounters() { - return Arrays.copyOf(mBucketCounts, mBucketCounts.length); - } - - /** - * Returns the predefined endpoints for the histogram. - * - * @return array of integers representing the endpoints for the predefined histogram count - * buckets. This value cannot be null. - */ - public @NonNull int[] getBucketEndpointsMillis() { - return Arrays.copyOf(sBucketEndpoints, sBucketEndpoints.length); - } - - // This takes the overrun time and returns what bucket it belongs to in the counters array. - private int getIndexForCountsFromOverrunTime(int overrunTime) { - if (overrunTime < 20) { - if (overrunTime >= -20) { - return (overrunTime + 20) / 2 + 12; - } - if (overrunTime >= -30) { - return (overrunTime + 30) / 5 + 10; - } - if (overrunTime >= -100) { - return (overrunTime + 100) / 10 + 3; - } - if (overrunTime >= -200) { - return (overrunTime + 200) / 50 + 1; - } - return 0; - } - if (overrunTime < 30) { - return (overrunTime - 20) / 5 + 32; - } - if (overrunTime < 100) { - return (overrunTime - 30) / 10 + 34; - } - if (overrunTime < 200) { - return (overrunTime - 50) / 100 + 41; - } - if (overrunTime < 1000) { - return (overrunTime - 200) / 100 + 43; - } - return sBucketEndpoints.length - 1; - } -} diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index c9472598b352..b4c293eeb695 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -111,7 +111,7 @@ public class JankDataProcessor { pendingStat.mTotalFrames += jankStat.getTotalFrameCount(); mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets, - jankStat.getFrameOverrunHistogram().getBucketCounters()); + jankStat.getRelativeFrameTimeHistogram().getBucketCounters()); } private void mergeNewStat(String stateKey, String activityName, AppJankStats jankStats) { @@ -136,7 +136,7 @@ public class JankDataProcessor { pendingStat.mJankyFrames = jankStats.getJankyFrameCount(); mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets, - jankStats.getFrameOverrunHistogram().getBucketCounters()); + jankStats.getRelativeFrameTimeHistogram().getBucketCounters()); mPendingJankStats.put(stateKey, pendingStat); } @@ -271,7 +271,8 @@ public class JankDataProcessor { private static final int[] sFrameOverrunHistogramBounds = { Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, - 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000 + 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000, + Integer.MAX_VALUE }; private final int[] mFrameOverrunBuckets = new int[sFrameOverrunHistogramBounds.length]; @@ -414,7 +415,7 @@ public class JankDataProcessor { if (overrunTime < 200) { return (overrunTime - 50) / 100 + 41; } - if (overrunTime < 1000) { + if (overrunTime <= 1000) { return (overrunTime - 200) / 100 + 43; } return sFrameOverrunHistogramBounds.length - 1; diff --git a/core/java/android/app/jank/RelativeFrameTimeHistogram.java b/core/java/android/app/jank/RelativeFrameTimeHistogram.java new file mode 100644 index 000000000000..666f90f89f45 --- /dev/null +++ b/core/java/android/app/jank/RelativeFrameTimeHistogram.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.jank; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; + +import java.util.Arrays; + +/** + * A histogram of frame times relative to their deadline. + * + * This class aids in reporting {@link AppJankStats} to the system and is designed for use by + * library widgets. It facilitates the recording of frame times in relation to the frame deadline. + * The class records the distribution of time remaining until a frame is considered janky or how + * janky the frame was. + * <p> + * A frame's relative frame time value indicates whether it was delivered early, on time, or late. + * A negative relative frame time value indicates the frame was delivered early, a value of zero + * indicates the frame was delivered on time and a positive value indicates the frame was delivered + * late. The values of the endpoints indicate how early or late a frame was delivered. + * <p> + * The relative frame times are recorded as a histogram: values are + * {@link #addRelativeFrameTimeMillis added} to a bucket by increasing the bucket's counter. The + * count of frames with a relative frame time between + * {@link #getBucketEndpointsMillis bucket endpoints} {@code i} and {@code i+1} can be obtained + * through index {@code i} of {@link #getBucketCounters}. + * + */ +@FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) +public class RelativeFrameTimeHistogram { + private static int[] sBucketEndpoints = new int[]{ + Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18, + -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, 30, 40, + 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000, + Integer.MAX_VALUE + }; + // + private int[] mBucketCounts; + + /** + * Create a new instance of RelativeFrameTimeHistogram. + */ + public RelativeFrameTimeHistogram() { + mBucketCounts = new int[sBucketEndpoints.length - 1]; + } + + /** + * Increases the count by one for the bucket representing the relative frame time. + * + * @param frameTimeMillis relative frame time in millis, relative frame time is the difference + * between a frames deadline and when it was rendered. + */ + public void addRelativeFrameTimeMillis(int frameTimeMillis) { + int countsIndex = getRelativeFrameTimeBucketIndex(frameTimeMillis); + mBucketCounts[countsIndex]++; + } + + /** + * Returns the counts for the all the relative frame time buckets. + * + * @return an array of integers representing the counts of relative frame times. This value + * cannot be null. + */ + public @NonNull int[] getBucketCounters() { + return Arrays.copyOf(mBucketCounts, mBucketCounts.length); + } + + /** + * Returns the relative frame time endpoints for the histogram. + * <p> + * Index {@code i} of {@link #getBucketCounters} contains the count of frames that had a + * relative frame time between {@code endpoints[i]} (inclusive) and {@code endpoints[i+1]} + * (exclusive). + * + * @return array of integers representing the endpoints for the predefined histogram count + * buckets. This value cannot be null. + */ + public @NonNull int[] getBucketEndpointsMillis() { + return Arrays.copyOf(sBucketEndpoints, sBucketEndpoints.length); + } + + // This takes the relative frame time and returns what bucket it belongs to in the counters + // array. + private int getRelativeFrameTimeBucketIndex(int relativeFrameTime) { + if (relativeFrameTime < 20) { + if (relativeFrameTime >= -20) { + return (relativeFrameTime + 20) / 2 + 12; + } + if (relativeFrameTime >= -30) { + return (relativeFrameTime + 30) / 5 + 10; + } + if (relativeFrameTime >= -100) { + return (relativeFrameTime + 100) / 10 + 3; + } + if (relativeFrameTime >= -200) { + return (relativeFrameTime + 200) / 50 + 1; + } + return 0; + } + if (relativeFrameTime < 30) { + return (relativeFrameTime - 20) / 5 + 32; + } + if (relativeFrameTime < 100) { + return (relativeFrameTime - 30) / 10 + 34; + } + if (relativeFrameTime < 200) { + return (relativeFrameTime - 50) / 100 + 41; + } + if (relativeFrameTime < 1000) { + return (relativeFrameTime - 200) / 100 + 43; + } + return mBucketCounts.length - 1; + } +} diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig index 238f1cb12208..2569f7b99dca 100644 --- a/core/java/android/app/performance.aconfig +++ b/core/java/android/app/performance.aconfig @@ -32,7 +32,7 @@ flag { name: "pic_isolated_cache_statistics" is_fixed_read_only: true description: "Collects statistics for cache UID isolation strategies" - bug: "373752556" + bug: "379098894" } flag { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 9f898b823a76..e6ddbf466cae 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -196,6 +196,21 @@ interface IPackageManager { ProviderInfo resolveContentProvider(String name, long flags, int userId); /** + * Resolve content providers with a given authority, for a specific + * callingUid. + * + * @param authority Authority of the content provider + * @param flags Additional option flags to modify the data returned. + * @param userId Current user ID + * @param callingUid UID of the caller who's access to the content provider + is to be checked + * + * @return ProviderInfo of the resolved content provider. May return null + */ + ProviderInfo resolveContentProviderForUid(String authority, long flags, + int userId, int callingUid); + + /** * Retrieve sync information for all content providers. * * @param outNames Filled in with a list of the root names of the content diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 438a21b7942f..c16582f19c9b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8349,6 +8349,25 @@ public abstract class PackageManager { } /** + * Resolve content providers with a given authority, for a specific callingUid. + * @param authority Authority of the content provider + * @param flags Additional option flags to modify the data returned. + * @param callingUid UID of the caller who's access to the content provider is to be checked + + * @return ProviderInfo of the resolved content provider. + * @hide + */ + @Nullable + @FlaggedApi(android.content.pm.Flags.FLAG_UID_BASED_PROVIDER_LOOKUP) + @RequiresPermission(Manifest.permission.RESOLVE_COMPONENT_FOR_UID) + @SystemApi + public ProviderInfo resolveContentProviderForUid(@NonNull String authority, + @NonNull ComponentInfoFlags flags, int callingUid) { + throw new UnsupportedOperationException( + "resolveContentProviderForUid not implemented in subclass"); + } + + /** * Retrieve content provider information. * <p> * <em>Note: unlike most other methods, an empty result set is indicated diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index 0d219a901b9d..7bba06c87813 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -152,7 +152,7 @@ flag { name: "cache_sdk_system_features" namespace: "system_performance" description: "Feature flag to enable optimized cache for SDK-defined system feature lookups." - bug: "375000483" + bug: "326623529" } flag { @@ -375,3 +375,11 @@ flag { description: "Feature flag to remove the consumption of the hidden module status (ModuleInfo#IsHidden) in the Android source tree." bug: "363952383" } + +flag { + name: "uid_based_provider_lookup" + is_exported: true + namespace: "package_manager_service" + bug: "334024639" + description: "Feature flag to check whether a given UID can access a content provider" +} diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 852f04793f15..9c6b71b72ec8 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -417,6 +417,7 @@ public abstract class CameraDevice implements AutoCloseable { * or if any of the output configurations sets a stream use * case different from {@link * android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT}. + * @throws UnsupportedOperationException if the camera has been opened in shared mode * @see CameraExtensionCharacteristics#getSupportedExtensions * @see CameraExtensionCharacteristics#getExtensionSupportedSizes */ @@ -1258,7 +1259,8 @@ public abstract class CameraDevice implements AutoCloseable { * configurations are empty; or the session configuration * executor is invalid; * or the output dynamic range combination is - * invalid/unsupported. + * invalid/unsupported; or the session type is not shared when + * camera has been opened in shared mode. * @throws CameraAccessException In case the camera device is no longer connected or has * encountered a fatal error. * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) @@ -1292,6 +1294,8 @@ public abstract class CameraDevice implements AutoCloseable { * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if the camera device has been closed + * @throws UnsupportedOperationException if this is not a primary client of a camera opened in + * shared mode */ @NonNull public abstract CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType) @@ -1328,6 +1332,8 @@ public abstract class CameraDevice implements AutoCloseable { * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if the camera device has been closed + * @throws UnsupportedOperationException if this is not a primary client of a camera opened in + * shared mode * * @see #TEMPLATE_PREVIEW * @see #TEMPLATE_RECORD @@ -1369,6 +1375,7 @@ public abstract class CameraDevice implements AutoCloseable { * @throws CameraAccessException if the camera device is no longer connected or has * encountered a fatal error * @throws IllegalStateException if the camera device has been closed + * @throws UnsupportedOperationException if the camera has been opened in shared mode * * @see CaptureRequest.Builder * @see TotalCaptureResult diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index aba2345f28d8..bfaff941939c 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -1375,6 +1375,9 @@ public final class CameraManager { * @throws SecurityException if the application does not have permission to * access the camera * + * @throws UnsupportedOperationException if {@link #isCameraDeviceSharingSupported} returns + * false for the given {@code cameraId}. + * * @see #getCameraIdList * @see android.app.admin.DevicePolicyManager#setCameraDisabled * @@ -1393,6 +1396,10 @@ public final class CameraManager { if (executor == null) { throw new IllegalArgumentException("executor was null"); } + if (!isCameraDeviceSharingSupported(cameraId)) { + throw new UnsupportedOperationException( + "CameraDevice sharing is not supported for Camera ID: " + cameraId); + } openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0, getRotationOverride(mContext), /*sharedMode*/true); } diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 496d316eb028..1c65b0882e0f 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -299,6 +299,24 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> return mRequestType; } + /** + * Get the stream ids corresponding to the target surfaces. + * + * @hide + */ + public int[] getStreamIds() { + return mStreamIdxArray; + }; + + /** + * Get the surface ids corresponding to the target surfaces. + * + * @hide + */ + public int[] getSurfaceIds() { + return mSurfaceIdxArray; + }; + // If this request is part of constrained high speed request list that was created by // {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList} private boolean mIsPartOfCHSRequestList = false; diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index ce8661e90978..7e0456b22be8 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -340,6 +340,30 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession } } + /** + * Shared Camera capture session API which can be used by the clients + * to start streaming. + * + * @hide + */ + public int startStreaming(List<Surface> surfaces, Executor executor, + CaptureCallback callback) throws CameraAccessException { + + synchronized (mDeviceImpl.mInterfaceLock) { + checkNotClosed(); + + executor = CameraDeviceImpl.checkExecutor(executor, callback); + + if (DEBUG) { + Log.v(TAG, mIdString + "startStreaming callback " + callback + " executor" + + " " + executor); + } + + return addPendingSequence(mDeviceImpl.startStreaming(surfaces, + createCaptureCallbackProxyWithExecutor(executor, callback), mDeviceExecutor)); + } + } + private void checkRepeatingRequest(CaptureRequest request) { if (request == null) { throw new IllegalArgumentException("request must not be null"); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 34c0f7b19da9..89a6b02b56c4 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -451,6 +451,16 @@ public class CameraDeviceImpl extends CameraDevice } } + /** + * When camera device is opened in shared mode, call to check if this is a primary client. + * + */ + public boolean isPrimaryClient() { + synchronized (mInterfaceLock) { + return mIsPrimaryClient; + } + } + private Map<String, CameraCharacteristics> getPhysicalIdToChars() { if (mPhysicalIdsToChars == null) { try { @@ -482,8 +492,19 @@ public class CameraDeviceImpl extends CameraDevice mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice); Parcel resultParcel = Parcel.obtain(); - mRemoteDevice.getCaptureResultMetadataQueue().writeToParcel(resultParcel, 0); + + // Passing in PARCELABLE_WRITE_RETURN_VALUE closes the ParcelFileDescriptors + // owned by MQDescriptor returned by getCaptureResultMetadataQueue() + // Though these will be closed when GC runs, that may not happen for a while. + // Also, apps running with StrictMode would get warnings / crash in the case they're not + // explicitly closed. + mRemoteDevice.getCaptureResultMetadataQueue().writeToParcel(resultParcel, + Parcelable.PARCELABLE_WRITE_RETURN_VALUE); mFMQReader = nativeCreateFMQReader(resultParcel); + // Recycle since resultParcel would dup fds from MQDescriptor as well. We don't + // need them after the native FMQ reader has been created. That is since the native + // creates calls MQDescriptor.readFromParcel() which again dups the fds. + resultParcel.recycle(); IBinder remoteDeviceBinder = remoteDevice.asBinder(); // For legacy camera device, remoteDevice is in the same process, and @@ -847,24 +868,19 @@ public class CameraDeviceImpl extends CameraDevice List<SharedOutputConfiguration> sharedConfigs = sharedSessionConfiguration.getOutputStreamsInformation(); for (SharedOutputConfiguration sharedConfig : sharedConfigs) { - if (outConfig.getConfiguredSize().equals(sharedConfig.getSize()) - && (outConfig.getConfiguredFormat() == sharedConfig.getFormat()) - && (outConfig.getSurfaceGroupId() == OutputConfiguration.SURFACE_GROUP_ID_NONE) - && (outConfig.getSurfaceType() == sharedConfig.getSurfaceType()) + if ((outConfig.getSurfaceGroupId() == OutputConfiguration.SURFACE_GROUP_ID_NONE) && (outConfig.getMirrorMode() == sharedConfig.getMirrorMode()) - && (outConfig.getUsage() == sharedConfig.getUsage()) && (outConfig.isReadoutTimestampEnabled() == sharedConfig.isReadoutTimestampEnabled()) && (outConfig.getTimestampBase() == sharedConfig.getTimestampBase()) && (outConfig.getStreamUseCase() == sharedConfig.getStreamUseCase()) - && (outConfig.getColorSpace().equals( - sharedSessionConfiguration.getColorSpace())) && (outConfig.getDynamicRangeProfile() == DynamicRangeProfiles.STANDARD) - && (outConfig.getConfiguredDataspace() == sharedConfig.getDataspace()) && (Objects.equals(outConfig.getPhysicalCameraId(), sharedConfig.getPhysicalCameraId())) && (outConfig.getSensorPixelModes().isEmpty()) + && (!outConfig.isMultiResolution()) + && (!outConfig.isDeferredConfiguration()) && (!outConfig.isShared())) { //Found valid config, return true return true; @@ -896,14 +912,6 @@ public class CameraDeviceImpl extends CameraDevice if (config.getExecutor() == null) { throw new IllegalArgumentException("Invalid executor"); } - if (mSharedMode) { - if (config.getSessionType() != SessionConfiguration.SESSION_SHARED) { - throw new IllegalArgumentException("Invalid session type"); - } - if (!checkSharedSessionConfiguration(outputConfigs)) { - throw new IllegalArgumentException("Invalid output configurations"); - } - } createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs, config.getStateCallback(), config.getExecutor(), config.getSessionType(), config.getSessionParameters()); @@ -921,17 +929,26 @@ public class CameraDeviceImpl extends CameraDevice checkIfCameraClosedOrInError(); + boolean isSharedSession = (operatingMode == ICameraDeviceUser.SHARED_MODE); + if (Flags.cameraMultiClient() && mSharedMode) { + if (!isSharedSession) { + throw new IllegalArgumentException("Invalid session type"); + } + if (!checkSharedSessionConfiguration(outputConfigurations)) { + throw new IllegalArgumentException("Invalid output configurations"); + } + if (inputConfig != null) { + throw new IllegalArgumentException("Shared capture session doesn't support" + + " input configuration yet."); + } + } + boolean isConstrainedHighSpeed = (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE); if (isConstrainedHighSpeed && inputConfig != null) { throw new IllegalArgumentException("Constrained high speed session doesn't support" + " input configuration yet."); } - boolean isSharedSession = (operatingMode == ICameraDeviceUser.SHARED_MODE); - if (isSharedSession && inputConfig != null) { - throw new IllegalArgumentException("Shared capture session doesn't support" - + " input configuration yet."); - } if (mCurrentExtensionSession != null) { mCurrentExtensionSession.commitStats(); @@ -993,8 +1010,7 @@ public class CameraDeviceImpl extends CameraDevice mCharacteristics); } else if (isSharedSession) { newSession = new CameraSharedCaptureSessionImpl(mNextSessionId++, - callback, executor, this, mDeviceExecutor, configureSuccess, - mIsPrimaryClient); + callback, executor, this, mDeviceExecutor, configureSuccess); } else { newSession = new CameraCaptureSessionImpl(mNextSessionId++, input, callback, executor, this, mDeviceExecutor, configureSuccess); @@ -1063,6 +1079,11 @@ public class CameraDeviceImpl extends CameraDevice synchronized(mInterfaceLock) { checkIfCameraClosedOrInError(); + if (Flags.cameraMultiClient() && mSharedMode && !mIsPrimaryClient) { + throw new UnsupportedOperationException("In shared session mode," + + "only primary clients can create capture request."); + } + for (String physicalId : physicalCameraIdSet) { if (Objects.equals(physicalId, getId())) { throw new IllegalStateException("Physical id matches the logical id!"); @@ -1089,6 +1110,11 @@ public class CameraDeviceImpl extends CameraDevice synchronized(mInterfaceLock) { checkIfCameraClosedOrInError(); + if (Flags.cameraMultiClient() && mSharedMode && !mIsPrimaryClient) { + throw new UnsupportedOperationException("In shared session mode," + + "only primary clients can create capture request."); + } + CameraMetadataNative templatedRequest = null; templatedRequest = mRemoteDevice.createDefaultRequest(templateType); @@ -1108,6 +1134,10 @@ public class CameraDeviceImpl extends CameraDevice throws CameraAccessException { synchronized(mInterfaceLock) { checkIfCameraClosedOrInError(); + if (Flags.cameraMultiClient() && mSharedMode) { + throw new UnsupportedOperationException("In shared session mode," + + "reprocess capture requests are not supported."); + } CameraMetadataNative resultMetadata = new CameraMetadataNative(inputResult.getNativeCopy()); @@ -1561,6 +1591,74 @@ public class CameraDeviceImpl extends CameraDevice } } + public int startStreaming(List<Surface> surfaces, CaptureCallback callback, + Executor executor) throws CameraAccessException { + // Need a valid executor, or current thread needs to have a looper, if + // callback is valid + executor = checkExecutor(executor, callback); + synchronized (mInterfaceLock) { + checkIfCameraClosedOrInError(); + for (Surface surface : surfaces) { + if (surface == null) { + throw new IllegalArgumentException("Null Surface targets are not allowed"); + } + } + // In shared session mode, if there are other active clients streaming then + // stoprepeating does not actually send request to HAL to cancel the request. + // Cameraservice will use this call to remove this client surfaces provided in its + // previous streaming request. If this is the only client for the shared camera device + // then camerservice will ask HAL to cancel the previous repeating request + stopRepeating(); + + // StartStreaming API does not allow capture parameters to be provided through a capture + // request. If the primary client has an existing repeating request, the camera service + // will either attach the provided surfaces to that request or create a default capture + // request if no repeating request is active. A default capture request is created here + // for initial use. The capture callback will provide capture results that include the + // actual capture parameters used for the streaming. + CaptureRequest.Builder builder = createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + for (Surface surface : surfaces) { + builder.addTarget(surface); + } + CaptureRequest request = builder.build(); + request.convertSurfaceToStreamId(mConfiguredOutputs); + + SubmitInfo requestInfo; + requestInfo = mRemoteDevice.startStreaming(request.getStreamIds(), + request.getSurfaceIds()); + request.recoverStreamIdToSurface(); + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + requestList.add(request); + + if (callback != null) { + mCaptureCallbackMap.put(requestInfo.getRequestId(), + new CaptureCallbackHolder( + callback, requestList, executor, true, mNextSessionId - 1)); + } else { + if (DEBUG) { + Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null"); + } + } + + if (mRepeatingRequestId != REQUEST_ID_NONE) { + checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, + requestInfo.getLastFrameNumber(), mRepeatingRequestTypes); + } + + CaptureRequest[] requestArray = requestList.toArray( + new CaptureRequest[requestList.size()]); + mRepeatingRequestId = requestInfo.getRequestId(); + mRepeatingRequestTypes = getRequestTypes(requestArray); + + if (mIdle) { + mDeviceExecutor.execute(mCallOnActive); + } + mIdle = false; + + return requestInfo.getRequestId(); + } + } + public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback, Executor executor) throws CameraAccessException { List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); @@ -2883,6 +2981,11 @@ public class CameraDeviceImpl extends CameraDevice @Override public void createExtensionSession(ExtensionSessionConfiguration extensionConfiguration) throws CameraAccessException { + if (Flags.cameraMultiClient() && mSharedMode) { + throw new UnsupportedOperationException("In shared session mode," + + "extension sessions are not supported."); + } + HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>( getPhysicalIdToChars()); characteristicsMap.put(mCameraId, mCharacteristics); @@ -2918,4 +3021,4 @@ public class CameraDeviceImpl extends CameraDevice } } } -}
\ No newline at end of file +} diff --git a/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java index a1f31c0ced5e..8c0dcfb2a28c 100644 --- a/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java @@ -19,6 +19,8 @@ import android.annotation.FlaggedApi; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraOfflineSession; +import android.hardware.camera2.CameraOfflineSession.CameraOfflineSessionCallback; import android.hardware.camera2.CameraSharedCaptureSession; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.OutputConfiguration; @@ -28,6 +30,7 @@ import android.view.Surface; import com.android.internal.camera.flags.Flags; +import java.util.Collection; import java.util.List; import java.util.concurrent.Executor; @@ -46,7 +49,8 @@ public class CameraSharedCaptureSessionImpl private static final String TAG = "CameraSharedCaptureSessionImpl"; private final CameraCaptureSessionImpl mSessionImpl; private final ConditionVariable mInitialized = new ConditionVariable(); - private boolean mIsPrimary; + private final android.hardware.camera2.impl.CameraDeviceImpl mCameraDevice; + private final Executor mDeviceExecutor; /** * Create a new CameraCaptureSession. @@ -54,24 +58,32 @@ public class CameraSharedCaptureSessionImpl CameraSharedCaptureSessionImpl(int id, CameraCaptureSession.StateCallback callback, Executor stateExecutor, android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, - Executor deviceStateExecutor, boolean configureSuccess, boolean isPrimary) { + Executor deviceStateExecutor, boolean configureSuccess) { CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback); mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback, stateExecutor, deviceImpl, deviceStateExecutor, configureSuccess); - mIsPrimary = isPrimary; + mCameraDevice = deviceImpl; + mDeviceExecutor = deviceStateExecutor; mInitialized.open(); } @Override - public int startStreaming(List<Surface> surfaces, Executor executor, CaptureCallback listener) + public int startStreaming(List<Surface> surfaces, Executor executor, CaptureCallback callback) throws CameraAccessException { - // Todo: Need to add implementation. - return 0; + if (surfaces.isEmpty()) { + throw new IllegalArgumentException("No surfaces provided for streaming"); + } else if (executor == null) { + throw new IllegalArgumentException("executor must not be null"); + } else if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } + + return mSessionImpl.startStreaming(surfaces, executor, callback); } @Override public void stopStreaming() throws CameraAccessException { - // Todo: Need to add implementation. + mSessionImpl.stopRepeating(); } @Override @@ -90,16 +102,24 @@ public class CameraSharedCaptureSessionImpl } @Override + public boolean supportsOfflineProcessing(Surface surface) { + return false; + } + + @Override public void abortCaptures() throws CameraAccessException { - if (mIsPrimary) { + if (mCameraDevice.isPrimaryClient()) { mSessionImpl.abortCaptures(); + return; } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); } @Override public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener, Handler handler) throws CameraAccessException { - if (mIsPrimary) { + if (mCameraDevice.isPrimaryClient()) { return mSessionImpl.setRepeatingRequest(request, listener, handler); } throw new UnsupportedOperationException("Shared capture session only supports this method" @@ -107,16 +127,30 @@ public class CameraSharedCaptureSessionImpl } @Override + public int setSingleRepeatingRequest(CaptureRequest request, Executor executor, + CaptureCallback listener) + throws CameraAccessException { + if (mCameraDevice.isPrimaryClient()) { + return mSessionImpl.setSingleRepeatingRequest(request, executor, listener); + } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); + } + + @Override public void stopRepeating() throws CameraAccessException { - if (mIsPrimary) { + if (mCameraDevice.isPrimaryClient()) { mSessionImpl.stopRepeating(); + return; } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); } @Override public int capture(CaptureRequest request, CaptureCallback listener, Handler handler) throws CameraAccessException { - if (mIsPrimary) { + if (mCameraDevice.isPrimaryClient()) { return mSessionImpl.capture(request, listener, handler); } throw new UnsupportedOperationException("Shared capture session only supports this method" @@ -124,6 +158,17 @@ public class CameraSharedCaptureSessionImpl } @Override + public int captureSingleRequest(CaptureRequest request, Executor executor, + CaptureCallback listener) + throws CameraAccessException { + if (mCameraDevice.isPrimaryClient()) { + return mSessionImpl.captureSingleRequest(request, executor, listener); + } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); + } + + @Override public void tearDown(Surface surface) throws CameraAccessException { mSessionImpl.tearDown(surface); } @@ -149,48 +194,72 @@ public class CameraSharedCaptureSessionImpl } @Override + public CameraOfflineSession switchToOffline(Collection<Surface> offlineSurfaces, + Executor executor, CameraOfflineSessionCallback listener) + throws CameraAccessException { + throw new UnsupportedOperationException("Shared capture session do not support this method" + ); + } + + @Override public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener, Handler handler) throws CameraAccessException { - throw new UnsupportedOperationException("Shared Capture session doesn't support" + throw new UnsupportedOperationException("Shared Capture session do not support" + + " this method"); + } + + @Override + public int setRepeatingBurstRequests(List<CaptureRequest> requests, + Executor executor, CaptureCallback listener) + throws CameraAccessException { + throw new UnsupportedOperationException("Shared Capture session do not support" + " this method"); } @Override public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener, Handler handler) throws CameraAccessException { - throw new UnsupportedOperationException("Shared Capture session doesn't support" + throw new UnsupportedOperationException("Shared Capture session do not support" + + " this method"); + } + + @Override + public int captureBurstRequests(List<CaptureRequest> requests, + Executor executor, CaptureCallback listener) + throws CameraAccessException { + throw new UnsupportedOperationException("Shared Capture session do not support" + " this method"); } @Override public void updateOutputConfiguration(OutputConfiguration config) throws CameraAccessException { - throw new UnsupportedOperationException("Shared capture session doesn't support" + throw new UnsupportedOperationException("Shared capture session do not support" + " this method"); } @Override public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException { - throw new UnsupportedOperationException("Shared capture session doesn't support" + throw new UnsupportedOperationException("Shared capture session do not support" + " this method"); } @Override public void prepare(Surface surface) throws CameraAccessException { - throw new UnsupportedOperationException("Shared capture session doesn't support" + throw new UnsupportedOperationException("Shared capture session do not support" + " this method"); } @Override public void prepare(int maxCount, Surface surface) throws CameraAccessException { - throw new UnsupportedOperationException("Shared capture session doesn't support" + throw new UnsupportedOperationException("Shared capture session do not support" + " this method"); } @Override public void closeWithoutDraining() { - throw new UnsupportedOperationException("Shared capture session doesn't support" + throw new UnsupportedOperationException("Shared capture session do not support" + " this method"); } diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java index a79e084b7f41..0b8e9c2687c3 100644 --- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java +++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java @@ -65,6 +65,17 @@ public class ICameraDeviceUserWrapper { } } + public SubmitInfo startStreaming(int[] streamIdxArray, int[] surfaceIdxArray) + throws CameraAccessException { + try { + return mRemoteDevice.startStreaming(streamIdxArray, surfaceIdxArray); + } catch (ServiceSpecificException e) { + throw ExceptionUtils.throwAsPublicException(e); + } catch (RemoteException e) { + throw ExceptionUtils.throwAsPublicException(e); + } + } + public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) throws CameraAccessException { try { @@ -325,4 +336,4 @@ public class ICameraDeviceUserWrapper { } } -}
\ No newline at end of file +} diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index e12c46322d8c..d394154a2c0e 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -1803,6 +1803,19 @@ public final class OutputConfiguration implements Parcelable { } /** + * Get the flag indicating if this {@link OutputConfiguration} is for a multi-resolution output + * with a MultiResolutionImageReader. + * + * @return true if this {@link OutputConfiguration} is for a multi-resolution output with a + * MultiResolutionImageReader. + * + * @hide + */ + public boolean isMultiResolution() { + return mIsMultiResolution; + } + + /** * Get the physical camera ID associated with this {@link OutputConfiguration}. * * <p>If this OutputConfiguration isn't targeting a physical camera of a logical diff --git a/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java index cdcc92ce4404..365f870ba22d 100644 --- a/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java @@ -212,7 +212,7 @@ public final class SharedSessionConfiguration { } public @Nullable String getPhysicalCameraId() { - return mPhysicalCameraId; + return mPhysicalCameraId.isEmpty() ? null : mPhysicalCameraId; } } diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java index 99f331f43450..de88895ba55c 100644 --- a/core/java/android/hardware/contexthub/HubEndpoint.java +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -99,8 +99,8 @@ public class HubEndpoint { private final Object mLock = new Object(); private final HubEndpointInfo mPendingHubEndpointInfo; - @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback; - @Nullable private final IHubEndpointMessageCallback mMessageCallback; + @Nullable private final HubEndpointLifecycleCallback mLifecycleCallback; + @Nullable private final HubEndpointMessageCallback mMessageCallback; @NonNull private final Executor mLifecycleCallbackExecutor; @NonNull private final Executor mMessageCallbackExecutor; @@ -335,9 +335,9 @@ public class HubEndpoint { private HubEndpoint( @NonNull HubEndpointInfo pendingEndpointInfo, - @Nullable IHubEndpointLifecycleCallback endpointLifecycleCallback, + @Nullable HubEndpointLifecycleCallback endpointLifecycleCallback, @NonNull Executor lifecycleCallbackExecutor, - @Nullable IHubEndpointMessageCallback endpointMessageCallback, + @Nullable HubEndpointMessageCallback endpointMessageCallback, @NonNull Executor messageCallbackExecutor) { mPendingHubEndpointInfo = pendingEndpointInfo; mLifecycleCallback = endpointLifecycleCallback; @@ -485,12 +485,12 @@ public class HubEndpoint { } @Nullable - public IHubEndpointLifecycleCallback getLifecycleCallback() { + public HubEndpointLifecycleCallback getLifecycleCallback() { return mLifecycleCallback; } @Nullable - public IHubEndpointMessageCallback getMessageCallback() { + public HubEndpointMessageCallback getMessageCallback() { return mMessageCallback; } @@ -498,11 +498,11 @@ public class HubEndpoint { public static final class Builder { private final String mPackageName; - @Nullable private IHubEndpointLifecycleCallback mLifecycleCallback; + @Nullable private HubEndpointLifecycleCallback mLifecycleCallback; @NonNull private Executor mLifecycleCallbackExecutor; - @Nullable private IHubEndpointMessageCallback mMessageCallback; + @Nullable private HubEndpointMessageCallback mMessageCallback; @NonNull private Executor mMessageCallbackExecutor; private int mVersion; @@ -539,10 +539,13 @@ public class HubEndpoint { return this; } - /** Attach a callback interface for lifecycle events for this Endpoint */ + /** + * Attach a callback interface for lifecycle events for this Endpoint. Callback will be + * posted to the main thread. + */ @NonNull public Builder setLifecycleCallback( - @NonNull IHubEndpointLifecycleCallback lifecycleCallback) { + @NonNull HubEndpointLifecycleCallback lifecycleCallback) { mLifecycleCallback = lifecycleCallback; return this; } @@ -554,15 +557,18 @@ public class HubEndpoint { @NonNull public Builder setLifecycleCallback( @NonNull @CallbackExecutor Executor executor, - @NonNull IHubEndpointLifecycleCallback lifecycleCallback) { + @NonNull HubEndpointLifecycleCallback lifecycleCallback) { mLifecycleCallbackExecutor = executor; mLifecycleCallback = lifecycleCallback; return this; } - /** Attach a callback interface for message events for this Endpoint */ + /** + * Attach a callback interface for message events for this Endpoint. Callback will be posted + * to the main thread. + */ @NonNull - public Builder setMessageCallback(@NonNull IHubEndpointMessageCallback messageCallback) { + public Builder setMessageCallback(@NonNull HubEndpointMessageCallback messageCallback) { mMessageCallback = messageCallback; return this; } @@ -574,7 +580,7 @@ public class HubEndpoint { @NonNull public Builder setMessageCallback( @NonNull @CallbackExecutor Executor executor, - @NonNull IHubEndpointMessageCallback messageCallback) { + @NonNull HubEndpointMessageCallback messageCallback) { mMessageCallbackExecutor = executor; mMessageCallback = messageCallback; return this; diff --git a/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java b/core/java/android/hardware/contexthub/HubEndpointDiscoveryCallback.java index a61a7ebd0de9..4672bbb74170 100644 --- a/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java +++ b/core/java/android/hardware/contexthub/HubEndpointDiscoveryCallback.java @@ -30,7 +30,7 @@ import java.util.List; */ @SystemApi @FlaggedApi(Flags.FLAG_OFFLOAD_API) -public interface IHubEndpointDiscoveryCallback { +public interface HubEndpointDiscoveryCallback { /** * Called when a list of hub endpoints have started. * diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/HubEndpointLifecycleCallback.java index 698ed0adfd80..6d75010711cc 100644 --- a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java +++ b/core/java/android/hardware/contexthub/HubEndpointLifecycleCallback.java @@ -29,7 +29,7 @@ import android.chre.flags.Flags; */ @SystemApi @FlaggedApi(Flags.FLAG_OFFLOAD_API) -public interface IHubEndpointLifecycleCallback { +public interface HubEndpointLifecycleCallback { /** * Called when an endpoint is requesting a session be opened with another endpoint. * diff --git a/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java b/core/java/android/hardware/contexthub/HubEndpointMessageCallback.java index fde7017b5e76..5db54efc8893 100644 --- a/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java +++ b/core/java/android/hardware/contexthub/HubEndpointMessageCallback.java @@ -26,18 +26,18 @@ import android.chre.flags.Flags; * <p>This interface can be attached to an endpoint through {@link * HubEndpoint.Builder#setMessageCallback} method. Methods in this interface will only be called * when the endpoint is currently registered and has an open session. The endpoint will receive - * session lifecycle callbacks through {@link IHubEndpointLifecycleCallback}. + * session lifecycle callbacks through {@link HubEndpointLifecycleCallback}. * * @hide */ @SystemApi @FlaggedApi(Flags.FLAG_OFFLOAD_API) -public interface IHubEndpointMessageCallback { +public interface HubEndpointMessageCallback { /** * Callback interface for receiving messages for a particular endpoint session. * * @param session The session this message is sent through. Previously specified in a {@link - * IHubEndpointLifecycleCallback#onSessionOpened(HubEndpointSession)} call. + * HubEndpointLifecycleCallback#onSessionOpened(HubEndpointSession)} call. * @param message The {@link HubMessage} object representing a message received by the endpoint * that registered this callback interface. This message is constructed by the */ diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java index 77f937ebeabc..f7f5636264e4 100644 --- a/core/java/android/hardware/contexthub/HubEndpointSession.java +++ b/core/java/android/hardware/contexthub/HubEndpointSession.java @@ -137,7 +137,7 @@ public class HubEndpointSession implements AutoCloseable { * no service associated to this session. * * <p>For hub initiated sessions, the object was previously used in as an argument for open - * request in {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. + * request in {@link HubEndpointLifecycleCallback#onSessionOpenRequest}. * * <p>For app initiated sessions, the object was previously used in an open request in {@link * android.hardware.location.ContextHubManager#openSession} diff --git a/core/java/android/hardware/contexthub/HubEndpointSessionResult.java b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java index 1f2bdb985008..b193d00467aa 100644 --- a/core/java/android/hardware/contexthub/HubEndpointSessionResult.java +++ b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java @@ -23,7 +23,7 @@ import android.annotation.SystemApi; import android.chre.flags.Flags; /** - * Return type of {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. The value determines + * Return type of {@link HubEndpointLifecycleCallback#onSessionOpenRequest}. The value determines * whether a open session request from the remote is accepted or not. * * @hide diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java index 2f33e8f8872b..651be3b17c33 100644 --- a/core/java/android/hardware/contexthub/HubServiceInfo.java +++ b/core/java/android/hardware/contexthub/HubServiceInfo.java @@ -112,6 +112,7 @@ public final class HubServiceInfo implements Parcelable { * <p>The value can be one of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}. */ + @ServiceFormat public int getFormat() { return mFormat; } @@ -178,7 +179,8 @@ public final class HubServiceInfo implements Parcelable { * <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService * </ol> * - * @param serviceDescriptor The service descriptor. + * @param serviceDescriptor The service descriptor for the interface, provided by the + * vendor. * @param format One of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}. * @param majorVersion Breaking changes should be a major version bump. diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index ffa546067eff..9030810a1c1a 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -106,7 +106,7 @@ public final class DisplayManagerGlobal { @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = { EVENT_DISPLAY_ADDED, - EVENT_DISPLAY_CHANGED, + EVENT_DISPLAY_BASIC_CHANGED, EVENT_DISPLAY_REMOVED, EVENT_DISPLAY_BRIGHTNESS_CHANGED, EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED, @@ -119,7 +119,8 @@ public final class DisplayManagerGlobal { public @interface DisplayEvent {} public static final int EVENT_DISPLAY_ADDED = 1; - public static final int EVENT_DISPLAY_CHANGED = 2; + public static final int EVENT_DISPLAY_BASIC_CHANGED = 2; + public static final int EVENT_DISPLAY_REMOVED = 3; public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4; public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5; @@ -130,7 +131,7 @@ public final class DisplayManagerGlobal { @LongDef(prefix = {"INTERNAL_EVENT_FLAG_"}, flag = true, value = { INTERNAL_EVENT_FLAG_DISPLAY_ADDED, - INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED, INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED, INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, @@ -143,7 +144,7 @@ public final class DisplayManagerGlobal { public @interface InternalEventFlag {} public static final long INTERNAL_EVENT_FLAG_DISPLAY_ADDED = 1L << 0; - public static final long INTERNAL_EVENT_FLAG_DISPLAY_CHANGED = 1L << 1; + public static final long INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED = 1L << 1; public static final long INTERNAL_EVENT_FLAG_DISPLAY_REMOVED = 1L << 2; public static final long INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED = 1L << 3; public static final long INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED = 1L << 4; @@ -485,7 +486,7 @@ public final class DisplayManagerGlobal { // There can be racing condition between DMS and WMS callbacks, so force triggering the // listener to make sure the client can get the onDisplayChanged callback even if // DisplayInfo is not changed (Display read from both DisplayInfo and WindowConfiguration). - handleDisplayEvent(displayId, EVENT_DISPLAY_CHANGED, true /* forceUpdate */); + handleDisplayEvent(displayId, EVENT_DISPLAY_BASIC_CHANGED, true /* forceUpdate */); } private static Looper getLooperForHandler(@Nullable Handler handler) { @@ -518,7 +519,8 @@ public final class DisplayManagerGlobal { } if (mDispatchNativeCallbacks) { mask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE | INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; } if (!mTopologyListeners.isEmpty()) { @@ -571,7 +573,8 @@ public final class DisplayManagerGlobal { } info = getDisplayInfoLocked(displayId); - if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { + if ((event == EVENT_DISPLAY_BASIC_CHANGED + || event == EVENT_DISPLAY_REFRESH_RATE_CHANGED) && mDispatchNativeCallbacks) { // Choreographer only supports a single display, so only dispatch refresh rate // changes for the default display. if (displayId == Display.DEFAULT_DISPLAY) { @@ -1492,9 +1495,9 @@ public final class DisplayManagerGlobal { mListener.onDisplayAdded(displayId); } break; - case EVENT_DISPLAY_CHANGED: - if ((mInternalEventFlagsMask & INTERNAL_EVENT_FLAG_DISPLAY_CHANGED) - != 0) { + case EVENT_DISPLAY_BASIC_CHANGED: + if ((mInternalEventFlagsMask + & INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED) != 0) { if (info != null && (forceUpdate || !info.equals(mDisplayInfo))) { if (extraLogging()) { Slog.i(TAG, "Sending onDisplayChanged: Display Changed. Info: " @@ -1691,8 +1694,8 @@ public final class DisplayManagerGlobal { switch (event) { case EVENT_DISPLAY_ADDED: return "ADDED"; - case EVENT_DISPLAY_CHANGED: - return "CHANGED"; + case EVENT_DISPLAY_BASIC_CHANGED: + return "BASIC_CHANGED"; case EVENT_DISPLAY_REMOVED: return "REMOVED"; case EVENT_DISPLAY_BRIGHTNESS_CHANGED: @@ -1763,7 +1766,11 @@ public final class DisplayManagerGlobal { } if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { - baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CHANGED; + // 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; } if ((eventFlags diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index 211aefffa34c..ba5dfc094afb 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -129,14 +129,38 @@ public final class DisplayTopology implements Parcelable { } /** + * Update the size of a display and normalize the topology. + * @param displayId The logical display ID + * @param width The new width + * @param height The new height + * @return True if the topology has changed. + */ + public boolean updateDisplay(int displayId, float width, float height) { + TreeNode display = findDisplay(displayId, mRoot); + if (display == null) { + return false; + } + if (floatEquals(display.mWidth, width) && floatEquals(display.mHeight, height)) { + return false; + } + display.mWidth = width; + display.mHeight = height; + normalize(); + Slog.i(TAG, "Display with ID " + displayId + " updated, new width: " + width + + ", new height: " + height); + return true; + } + + /** * Remove a display from the topology. * The default topology is created from the remaining displays, as if they were reconnected * one by one. * @param displayId The logical display ID + * @return True if the display was present in the topology and removed. */ - public void removeDisplay(int displayId) { + public boolean removeDisplay(int displayId) { if (findDisplay(displayId, mRoot) == null) { - return; + return false; } Queue<TreeNode> queue = new ArrayDeque<>(); queue.add(mRoot); @@ -159,6 +183,7 @@ public final class DisplayTopology implements Parcelable { } else { Slog.i(TAG, "Display with ID " + displayId + " removed"); } + return true; } /** @@ -685,12 +710,12 @@ public final class DisplayTopology implements Parcelable { /** * The width of the display in density-independent pixels (dp). */ - private final float mWidth; + private float mWidth; /** * The height of the display in density-independent pixels (dp). */ - private final float mHeight; + private float mHeight; /** * The position of this display relative to its parent. diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 4fbdf7f5afc8..d88a9d44511e 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -56,15 +56,18 @@ interface IDisplayManager { void stopWifiDisplayScan(); // Requires CONFIGURE_WIFI_DISPLAY permission. + @EnforcePermission("CONFIGURE_WIFI_DISPLAY") void connectWifiDisplay(String address); // No permissions required. void disconnectWifiDisplay(); // Requires CONFIGURE_WIFI_DISPLAY permission. + @EnforcePermission("CONFIGURE_WIFI_DISPLAY") void renameWifiDisplay(String address, String alias); // Requires CONFIGURE_WIFI_DISPLAY permission. + @EnforcePermission("CONFIGURE_WIFI_DISPLAY") void forgetWifiDisplay(String address); // Requires CONFIGURE_WIFI_DISPLAY permission. @@ -169,6 +172,7 @@ interface IDisplayManager { void setBrightness(int displayId, float brightness); // Retrieves the display brightness. + @EnforcePermission("CONTROL_DISPLAY_BRIGHTNESS") float getBrightness(int displayId); // Temporarily sets the auto brightness adjustment factor. @@ -196,8 +200,7 @@ interface IDisplayManager { // Sets the HDR conversion mode for a device. // Requires MODIFY_HDR_CONVERSION_MODE permission. - @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" - + ".permission.MODIFY_HDR_CONVERSION_MODE)") + @EnforcePermission("MODIFY_HDR_CONVERSION_MODE") void setHdrConversionMode(in HdrConversionMode hdrConversionMode); HdrConversionMode getHdrConversionModeSetting(); HdrConversionMode getHdrConversionMode(); diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 313bad50e88e..c4d11cd8aff7 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -204,3 +204,10 @@ flag { description: "Allows the user to disable input scrolling acceleration for mouse." bug: "383555305" } + +flag { + name: "remove_fallback_modifiers" + namespace: "input" + description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent." + bug: "382545048" +} diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 1e0cc94612dd..0cd320981c93 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -36,11 +36,11 @@ import android.content.pm.PackageManager; import android.hardware.contexthub.ErrorCode; import android.hardware.contexthub.HubDiscoveryInfo; import android.hardware.contexthub.HubEndpoint; +import android.hardware.contexthub.HubEndpointDiscoveryCallback; import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.HubEndpointLifecycleCallback; import android.hardware.contexthub.HubServiceInfo; import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; -import android.hardware.contexthub.IHubEndpointDiscoveryCallback; -import android.hardware.contexthub.IHubEndpointLifecycleCallback; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; @@ -207,7 +207,7 @@ public final class ContextHubManager { private Handler mCallbackHandler; /** A map of endpoint discovery callbacks currently registered */ - private Map<IHubEndpointDiscoveryCallback, IContextHubEndpointDiscoveryCallback> + private Map<HubEndpointDiscoveryCallback, IContextHubEndpointDiscoveryCallback> mDiscoveryCallbacks = new ConcurrentHashMap<>(); /** @@ -718,7 +718,19 @@ public final class ContextHubManager { /** * Find a list of endpoints that provides a specific service. * - * @param serviceDescriptor Statically generated ID for an endpoint. + * <p>Service descriptor should uniquely identify the interface (scoped to type). Convention of + * the descriptor depend on interface type. + * + * <p>Examples: + * + * <ol> + * <li>AOSP-defined AIDL: android.hardware.something.IFoo/default + * <li>Vendor-defined AIDL: com.example.something.IBar/default + * <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService + * </ol> + * + * @param serviceDescriptor The service descriptor for a service provided by the hub. The value + * cannot be null or empty. * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery. * @throws IllegalArgumentException if the serviceDescriptor is empty/null. */ @@ -750,14 +762,15 @@ public final class ContextHubManager { /** * Creates an interface to invoke endpoint discovery callbacks to send down to the service. * - * @param callback the callback to invoke at the client process * @param executor the executor to invoke callbacks for this client + * @param callback the callback to invoke at the client process + * @param serviceDescriptor an optional descriptor to match discovery list with * @return the callback interface */ @FlaggedApi(Flags.FLAG_OFFLOAD_API) private IContextHubEndpointDiscoveryCallback createDiscoveryCallback( - IHubEndpointDiscoveryCallback callback, Executor executor, + HubEndpointDiscoveryCallback callback, @Nullable String serviceDescriptor) { return new IContextHubEndpointDiscoveryCallback.Stub() { @Override @@ -829,36 +842,36 @@ public final class ContextHubManager { } /** - * Equivalent to {@link #registerEndpointDiscoveryCallback(long, IHubEndpointDiscoveryCallback, - * Executor)} with the default executor in the main thread. + * Equivalent to {@link #registerEndpointDiscoveryCallback(Executor, + * HubEndpointDiscoveryCallback, long)} with the default executor in the main thread. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void registerEndpointDiscoveryCallback( - long endpointId, @NonNull IHubEndpointDiscoveryCallback callback) { + @NonNull HubEndpointDiscoveryCallback callback, long endpointId) { registerEndpointDiscoveryCallback( - endpointId, callback, new HandlerExecutor(Handler.getMain())); + new HandlerExecutor(Handler.getMain()), callback, endpointId); } /** * Registers a callback to be notified when the hub endpoint with the corresponding endpoint ID * has started or stopped. * - * @param endpointId The identifier of the hub endpoint. - * @param callback The callback to be invoked. * @param executor The executor to invoke the callback on. + * @param callback The callback to be invoked. + * @param endpointId The identifier of the hub endpoint. * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void registerEndpointDiscoveryCallback( - long endpointId, - @NonNull IHubEndpointDiscoveryCallback callback, - @NonNull Executor executor) { - Objects.requireNonNull(callback, "callback cannot be null"); + @NonNull Executor executor, + @NonNull HubEndpointDiscoveryCallback callback, + long endpointId) { Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); IContextHubEndpointDiscoveryCallback iCallback = - createDiscoveryCallback(callback, executor, null); + createDiscoveryCallback(executor, callback, null); try { mService.registerEndpointDiscoveryCallbackId(endpointId, iCallback); } catch (RemoteException e) { @@ -869,42 +882,42 @@ public final class ContextHubManager { } /** - * Equivalent to {@link #registerEndpointDiscoveryCallback(String, - * IHubEndpointDiscoveryCallback, Executor)} with the default executor in the main thread. + * Equivalent to {@link #registerEndpointDiscoveryCallback(Executor, + * HubEndpointDiscoveryCallback, String)} with the default executor in the main thread. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void registerEndpointDiscoveryCallback( - @NonNull String serviceDescriptor, @NonNull IHubEndpointDiscoveryCallback callback) { + @NonNull HubEndpointDiscoveryCallback callback, @NonNull String serviceDescriptor) { registerEndpointDiscoveryCallback( - serviceDescriptor, callback, new HandlerExecutor(Handler.getMain())); + new HandlerExecutor(Handler.getMain()), callback, serviceDescriptor); } /** * Registers a callback to be notified when the hub endpoint with the corresponding service * descriptor has started or stopped. * + * @param executor The executor to invoke the callback on. * @param serviceDescriptor The service descriptor of the hub endpoint. * @param callback The callback to be invoked. - * @param executor The executor to invoke the callback on. * @throws IllegalArgumentException if the serviceDescriptor is empty. * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void registerEndpointDiscoveryCallback( - @NonNull String serviceDescriptor, - @NonNull IHubEndpointDiscoveryCallback callback, - @NonNull Executor executor) { - Objects.requireNonNull(serviceDescriptor, "serviceDescriptor cannot be null"); - Objects.requireNonNull(callback, "callback cannot be null"); + @NonNull Executor executor, + @NonNull HubEndpointDiscoveryCallback callback, + @NonNull String serviceDescriptor) { Objects.requireNonNull(executor, "executor cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); + Objects.requireNonNull(serviceDescriptor, "serviceDescriptor cannot be null"); if (serviceDescriptor.isBlank()) { throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor); } IContextHubEndpointDiscoveryCallback iCallback = - createDiscoveryCallback(callback, executor, serviceDescriptor); + createDiscoveryCallback(executor, callback, serviceDescriptor); try { mService.registerEndpointDiscoveryCallbackDescriptor(serviceDescriptor, iCallback); } catch (RemoteException e) { @@ -924,7 +937,7 @@ public final class ContextHubManager { @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void unregisterEndpointDiscoveryCallback( - @NonNull IHubEndpointDiscoveryCallback callback) { + @NonNull HubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); IContextHubEndpointDiscoveryCallback iCallback = mDiscoveryCallbacks.remove(callback); if (iCallback == null) { @@ -1291,7 +1304,7 @@ public final class ContextHubManager { * service. * * <p>Context Hub Service will create the endpoint session and notify the registered endpoint. - * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback} + * The registered endpoint will receive callbacks on its {@link HubEndpointLifecycleCallback} * object regarding the lifecycle events of the session. * * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link @@ -1311,7 +1324,7 @@ public final class ContextHubManager { * described by a {@link HubServiceInfo} object. * * <p>Context Hub Service will create the endpoint session and notify the registered endpoint. - * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback} + * The registered endpoint will receive callbacks on its {@link HubEndpointLifecycleCallback} * object regarding the lifecycle events of the session. * * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link diff --git a/core/java/android/net/thread/flags.aconfig b/core/java/android/net/thread/flags.aconfig index afb982ba64ca..100d50d8e70c 100644 --- a/core/java/android/net/thread/flags.aconfig +++ b/core/java/android/net/thread/flags.aconfig @@ -17,5 +17,5 @@ flag { is_exported: true namespace: "thread_network" description: "Controls whether the Android Thread feature is enabled" - bug: "301473012" + bug: "384596973" } diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 8a0adfaede8a..ecd90e46e432 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -480,10 +480,10 @@ public class BaseBundle implements Parcel.ClassLoaderProvider { map.erase(); map.ensureCapacity(count); } - int numLazyValues = 0; + int[] numLazyValues = new int[]{0}; try { - numLazyValues = parcelledData.readArrayMap(map, count, !parcelledByNative, - /* lazy */ ownsParcel, this); + parcelledData.readArrayMap(map, count, !parcelledByNative, + /* lazy */ ownsParcel, this, numLazyValues); } catch (BadParcelableException e) { if (sShouldDefuse) { Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e); @@ -494,14 +494,14 @@ public class BaseBundle implements Parcel.ClassLoaderProvider { } finally { mWeakParcelledData = null; if (ownsParcel) { - if (numLazyValues == 0) { + if (numLazyValues[0] == 0) { recycleParcel(parcelledData); } else { mWeakParcelledData = new WeakReference<>(parcelledData); } } - mLazyValues = numLazyValues; + mLazyValues = numLazyValues[0]; mParcelledByNative = false; mMap = map; // Set field last as it is volatile diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 01222cdd38b3..18d2afb8b1b5 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -687,12 +687,18 @@ public final class BinderProxy implements IBinder { return removeFrozenStateChangeCallbackNative(wrappedCallback); } + public static boolean isFrozenStateChangeCallbackSupported() { + return isFrozenStateChangeCallbackSupportedNative(); + } + private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback) throws RemoteException; private native boolean removeFrozenStateChangeCallbackNative( FrozenStateChangeCallback callback); + private static native boolean isFrozenStateChangeCallbackSupportedNative(); + /** * Perform a dump on the remote object * diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index f3bb51490f20..727dcbaca4bf 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -4,6 +4,8 @@ per-file *Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNER # PowerManager per-file IPowerManager.aidl = file:/services/core/java/com/android/server/power/OWNERS +per-file IScreenTimeoutPolicyListener.aidl = file:/services/core/java/com/android/server/power/OWNERS +per-file IWakeLockCallback.aidl = file:/services/core/java/com/android/server/power/OWNERS per-file PowerManager.java = file:/services/core/java/com/android/server/power/OWNERS per-file PowerManagerInternal.java = file:/services/core/java/com/android/server/power/OWNERS diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 4bbc61c9f115..5ba6553a58c9 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -5565,7 +5565,7 @@ public final class Parcel { private void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal, int size, @Nullable ClassLoaderProvider loaderProvider) { - readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loaderProvider); + readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loaderProvider, null); } /** @@ -5575,18 +5575,17 @@ public final class Parcel { * @param lazy Whether to populate the map with lazy {@link Function} objects for * length-prefixed values. See {@link Parcel#readLazyValue(ClassLoader)} for more * details. - * @return a count of the lazy values in the map + * @param lazyValueCount number of lazy values added here * @hide */ - int readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted, - boolean lazy, @Nullable ClassLoaderProvider loaderProvider) { - int lazyValues = 0; + void readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted, + boolean lazy, @Nullable ClassLoaderProvider loaderProvider, int[] lazyValueCount) { while (size > 0) { String key = readString(); Object value = (lazy) ? readLazyValue(loaderProvider) : readValue( getClassLoader(loaderProvider)); if (value instanceof LazyValue) { - lazyValues++; + lazyValueCount[0]++; } if (sorted) { map.append(key, value); @@ -5598,7 +5597,6 @@ public final class Parcel { if (sorted) { map.validate(); } - return lazyValues; } /** diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index e2169925fdd3..289b98c9b1d4 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -41,6 +41,7 @@ public class TestLooperManager { private boolean mReleased; private boolean mLooperBlocked; + private final boolean mLooperIsMyLooper; /** * @hide @@ -54,8 +55,11 @@ public class TestLooperManager { } mLooper = looper; mQueue = mLooper.getQueue(); - // Post a message that will keep the looper blocked as long as we are dispatching. - new Handler(looper).post(new LooperHolder()); + mLooperIsMyLooper = Looper.myLooper() == looper; + if (!mLooperIsMyLooper) { + // Post a message that will keep the looper blocked as long as we are dispatching. + new Handler(looper).post(new LooperHolder()); + } } /** @@ -82,7 +86,7 @@ public class TestLooperManager { 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 (!mLooperBlocked) { + while (!mLooperIsMyLooper && !mLooperBlocked) { synchronized (this) { try { wait(); @@ -114,9 +118,6 @@ public class TestLooperManager { * should be executed by this queue. * If the queue is empty or no messages are deliverable, returns null. * This method never blocks. - * - * <p>Callers should always call {@link #recycle(Message)} on the message when all interactions - * with it have completed. */ @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) @SuppressWarnings("AutoBoxing") // box the primitive long, or return null to indicate no value @@ -165,6 +166,9 @@ public class TestLooperManager { // This is being called from the thread it should be executed on, we can just dispatch. message.target.dispatchMessage(message); } else { + if (mLooperIsMyLooper) { + throw new RuntimeException("Cannot call execute from non Looper thread"); + } MessageExecution execution = new MessageExecution(); execution.m = message; synchronized (execution) { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 132805da7c94..507bcb8c2717 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -940,10 +940,10 @@ public class UserManager { /** * Specifies if a user is disallowed from resetting network settings - * from Settings. This can only be set by device owners and profile owners on the primary user. + * from Settings. This can only be set by device owners and profile owners on the main user. * The default value is <code>false</code>. - * <p>This restriction has no effect on secondary users and managed profiles since only the - * primary user can reset the network settings of the device. + * <p>This restriction has no effect on non-Admin users since they cannot reset the network + * settings of the device. * * <p>Holders of the permission * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_MOBILE_NETWORK} @@ -1077,11 +1077,11 @@ public class UserManager { /** * Specifies if a user is disallowed from configuring cell broadcasts. * - * <p>This restriction can only be set by a device owner, a profile owner on the primary + * <p>This restriction can only be set by a device owner, a profile owner on the main * user or a profile owner of an organization-owned managed profile on the parent profile. * When it is set by a device owner, it applies globally. When it is set by a profile owner - * on the primary user or by a profile owner of an organization-owned managed profile on - * the parent profile, it disables the primary user from configuring cell broadcasts. + * on the main user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the user from configuring cell broadcasts. * * <p>Holders of the permission * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_MOBILE_NETWORK} @@ -1089,8 +1089,8 @@ public class UserManager { * * <p>The default value is <code>false</code>. * - * <p>This restriction has no effect on secondary users and managed profiles since only the - * primary user can configure cell broadcasts. + * <p>This restriction has no effect on non-Admin users since they cannot configure cell + * broadcasts. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -1103,11 +1103,11 @@ public class UserManager { /** * Specifies if a user is disallowed from configuring mobile networks. * - * <p>This restriction can only be set by a device owner, a profile owner on the primary + * <p>This restriction can only be set by a device owner, a profile owner on the main * user or a profile owner of an organization-owned managed profile on the parent profile. * When it is set by a device owner, it applies globally. When it is set by a profile owner - * on the primary user or by a profile owner of an organization-owned managed profile on - * the parent profile, it disables the primary user from configuring mobile networks. + * on the main user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the user from configuring mobile networks. * * <p>Holders of the permission * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_MOBILE_NETWORK} @@ -1115,8 +1115,8 @@ public class UserManager { * * <p>The default value is <code>false</code>. * - * <p>This restriction has no effect on secondary users and managed profiles since only the - * primary user can configure mobile networks. + * <p>This restriction has no effect on non-Admin users since they cannot configure mobile + * networks. * * <p>Key for user restrictions. * <p>Type: Boolean diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c3a49305af87..6898fcef23ab 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1296,6 +1296,22 @@ public final class Settings { public static final String ACTION_LOCKSCREEN_SETTINGS = "android.settings.LOCK_SCREEN_SETTINGS"; /** + * Activity Action: Show settings of notifications on lockscreen. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_LOCKSCREEN_NOTIFICATIONS_SETTINGS = + "android.settings.LOCK_SCREEN_NOTIFICATIONS_SETTINGS"; + + /** * Activity Action: Show settings to allow pairing bluetooth devices. * <p> * In some cases, a matching Activity may not exist, so ensure you diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java index a086bf7f8b08..d476d960890b 100644 --- a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java +++ b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java @@ -30,26 +30,25 @@ import android.security.Flags; @FlaggedApi(Flags.FLAG_AAPM_API) @SystemApi public final class AdvancedProtectionFeature implements Parcelable { - private final String mId; + private final int mId; /** * Create an object identifying an Advanced Protection feature for AdvancedProtectionManager - * @param id A unique ID to identify this feature. It is used by Settings screens to display - * information about this feature. + * @param id Feature identifier. It is used by Settings screens to display information about + * this feature. */ - public AdvancedProtectionFeature(@NonNull String id) { + public AdvancedProtectionFeature(@AdvancedProtectionManager.FeatureId int id) { mId = id; } private AdvancedProtectionFeature(Parcel in) { - mId = in.readString8(); + mId = in.readInt(); } /** * @return the unique ID representing this feature */ - @NonNull - public String getId() { + public int getId() { return mId; } @@ -60,7 +59,7 @@ public final class AdvancedProtectionFeature implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString8(mId); + dest.writeInt(mId); } @NonNull diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java index 59628e8e69d7..ea01fc98eda0 100644 --- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java +++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java @@ -24,17 +24,18 @@ import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; +import android.net.wifi.WifiManager; import android.os.Binder; import android.os.RemoteException; +import android.os.UserManager; import android.security.Flags; import android.util.Log; @@ -59,54 +60,57 @@ public final class AdvancedProtectionManager { private static final String TAG = "AdvancedProtectionMgr"; /** - * Advanced Protection's identifier for setting policies or restrictions in DevicePolicyManager. + * Advanced Protection's identifier for setting policies or restrictions in + * {@link DevicePolicyManager}. * * @hide */ public static final String ADVANCED_PROTECTION_SYSTEM_ENTITY = "android.security.advancedprotection"; /** - * Feature identifier for disallowing 2G. + * Feature identifier for disallowing connections to 2G networks. * + * @see UserManager#DISALLOW_CELLULAR_2G * @hide */ @SystemApi - public static final String FEATURE_ID_DISALLOW_CELLULAR_2G = - "android.security.advancedprotection.feature_disallow_2g"; + public static final int FEATURE_ID_DISALLOW_CELLULAR_2G = 0; /** - * Feature identifier for disallowing install of unknown sources. + * Feature identifier for disallowing installs of apps from unknown sources. * + * @see UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY * @hide */ @SystemApi - public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = - "android.security.advancedprotection.feature_disallow_install_unknown_sources"; + public static final int FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = 1; /** - * Feature identifier for disallowing USB. + * Feature identifier for disallowing USB connections. * * @hide */ @SystemApi - public static final String FEATURE_ID_DISALLOW_USB = - "android.security.advancedprotection.feature_disallow_usb"; + public static final int FEATURE_ID_DISALLOW_USB = 2; /** - * Feature identifier for disallowing WEP. + * Feature identifier for disallowing connections to Wi-Fi Wired Equivalent Privacy (WEP) + * networks. * + * @see WifiManager#isWepSupported() * @hide */ @SystemApi - public static final String FEATURE_ID_DISALLOW_WEP = - "android.security.advancedprotection.feature_disallow_wep"; + public static final int FEATURE_ID_DISALLOW_WEP = 3; /** - * Feature identifier for enabling MTE. + * Feature identifier for enabling the Memory Tagging Extension (MTE). MTE is a CPU extension + * that allows to protect against certain classes of security problems at a small runtime + * performance cost overhead. * + * @see DevicePolicyManager#setMtePolicy(int) * @hide */ @SystemApi - public static final String FEATURE_ID_ENABLE_MTE = - "android.security.advancedprotection.feature_enable_mte"; + public static final int FEATURE_ID_ENABLE_MTE = 4; /** @hide */ - @StringDef(prefix = { "FEATURE_ID_" }, value = { + @IntDef(prefix = { "FEATURE_ID_" }, value = { FEATURE_ID_DISALLOW_CELLULAR_2G, FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES, FEATURE_ID_DISALLOW_USB, @@ -116,7 +120,7 @@ public final class AdvancedProtectionManager { @Retention(RetentionPolicy.SOURCE) public @interface FeatureId {} - private static final Set<String> ALL_FEATURE_IDS = Set.of( + private static final Set<Integer> ALL_FEATURE_IDS = Set.of( FEATURE_ID_DISALLOW_CELLULAR_2G, FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES, FEATURE_ID_DISALLOW_USB, @@ -135,9 +139,6 @@ public final class AdvancedProtectionManager { * Output: Nothing. * * @hide */ - @SystemApi - @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) - @FlaggedApi(android.security.Flags.FLAG_AAPM_API) public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG"; @@ -147,7 +148,6 @@ public final class AdvancedProtectionManager { * * @hide */ @FeatureId - @SystemApi public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE"; @@ -157,37 +157,41 @@ public final class AdvancedProtectionManager { * * @hide */ @SupportDialogType - @SystemApi public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE"; /** + * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating an unknown action was blocked by + * advanced protection, hence the support dialog should display a default explanation. + * + * @hide */ + public static final int SUPPORT_DIALOG_TYPE_UNKNOWN = 0; + + /** * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user performed an action that was * blocked by advanced protection. * * @hide */ - @SystemApi - public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = - "android.security.advancedprotection.type_blocked_interaction"; + public static final int SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = 1; /** * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user pressed on a setting toggle * that was disabled by advanced protection. * * @hide */ - @SystemApi - public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING = - "android.security.advancedprotection.type_disabled_setting"; + public static final int SUPPORT_DIALOG_TYPE_DISABLED_SETTING = 2; /** @hide */ - @StringDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = { + @IntDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = { + SUPPORT_DIALOG_TYPE_UNKNOWN, SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION, SUPPORT_DIALOG_TYPE_DISABLED_SETTING, }) @Retention(RetentionPolicy.SOURCE) public @interface SupportDialogType {} - private static final Set<String> ALL_SUPPORT_DIALOG_TYPES = Set.of( + private static final Set<Integer> ALL_SUPPORT_DIALOG_TYPES = Set.of( + SUPPORT_DIALOG_TYPE_UNKNOWN, SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION, SUPPORT_DIALOG_TYPE_DISABLED_SETTING); @@ -324,15 +328,13 @@ public final class AdvancedProtectionManager { * disabled by advanced protection. * @hide */ - @SystemApi - public @NonNull Intent createSupportIntent(@NonNull @FeatureId String featureId, - @Nullable @SupportDialogType String type) { - Objects.requireNonNull(featureId); + public static @NonNull Intent createSupportIntent(@FeatureId int featureId, + @SupportDialogType int type) { if (!ALL_FEATURE_IDS.contains(featureId)) { throw new IllegalArgumentException(featureId + " is not a valid feature ID. See" + " FEATURE_ID_* APIs."); } - if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) { + if (!ALL_SUPPORT_DIALOG_TYPES.contains(type)) { throw new IllegalArgumentException(type + " is not a valid type. See" + " SUPPORT_DIALOG_TYPE_* APIs."); } @@ -340,21 +342,19 @@ public final class AdvancedProtectionManager { Intent intent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG); intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, featureId); - if (type != null) { - intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type); - } + intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type); return intent; } /** @hide */ - public @NonNull Intent createSupportIntentForPolicyIdentifierOrRestriction( - @NonNull String identifier, @Nullable @SupportDialogType String type) { + public static @NonNull Intent createSupportIntentForPolicyIdentifierOrRestriction( + @NonNull String identifier, @SupportDialogType int type) { Objects.requireNonNull(identifier); - if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) { + if (!ALL_SUPPORT_DIALOG_TYPES.contains(type)) { throw new IllegalArgumentException(type + " is not a valid type. See" + " SUPPORT_DIALOG_TYPE_* APIs."); } - final String featureId; + final int featureId; if (DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY.equals(identifier)) { featureId = FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES; } else if (DISALLOW_CELLULAR_2G.equals(identifier)) { diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java index 90136ae00f6a..ffe8086ca4a1 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java @@ -93,6 +93,10 @@ import android.util.Log; * must do its own state management (keeping in mind that the service's process might be killed * by the Android System when unbound; for example, if the device is running low in memory). * + * <p> The service also provides pending intents to override the system's Quick Access activities + * via the {@link #getTargetActivityPendingIntent} and the + * {@link #getGestureTargetActivityPendingIntent} method. + * * <p> * <a name="ErrorHandling"></a> * <h3>Error handling</h3> @@ -384,6 +388,10 @@ public abstract class QuickAccessWalletService extends Service { * * <p>The pending intent will be sent when the user performs a gesture to open Wallet. * The pending intent should launch an activity. + * + * <p> If the gesture is performed and this method returns null, the system will launch the + * activity specified by the {@link #getTargetActivityPendingIntent} method. If that method + * also returns null, the system will launch the system-provided card switcher activity. */ @Nullable @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) diff --git a/core/java/android/service/settings/preferences/GetValueRequest.java b/core/java/android/service/settings/preferences/GetValueRequest.java index 4f82800d1855..db5c57c49595 100644 --- a/core/java/android/service/settings/preferences/GetValueRequest.java +++ b/core/java/android/service/settings/preferences/GetValueRequest.java @@ -108,6 +108,7 @@ public final class GetValueRequest implements Parcelable { /** * Builder to construct {@link GetValueRequest}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { private final String mScreenKey; private final String mPreferenceKey; diff --git a/core/java/android/service/settings/preferences/GetValueResult.java b/core/java/android/service/settings/preferences/GetValueResult.java index 369dea77cc85..791131588034 100644 --- a/core/java/android/service/settings/preferences/GetValueResult.java +++ b/core/java/android/service/settings/preferences/GetValueResult.java @@ -170,6 +170,7 @@ public final class GetValueResult implements Parcelable { /** * Builder to construct {@link GetValueResult}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { @ResultCode private final int mResultCode; diff --git a/core/java/android/service/settings/preferences/MetadataRequest.java b/core/java/android/service/settings/preferences/MetadataRequest.java index ffecc6bec5b2..e0417152eedc 100644 --- a/core/java/android/service/settings/preferences/MetadataRequest.java +++ b/core/java/android/service/settings/preferences/MetadataRequest.java @@ -65,6 +65,7 @@ public final class MetadataRequest implements Parcelable { /** * Builder to construct {@link MetadataRequest}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { /** Constructs an immutable {@link MetadataRequest} object. */ @NonNull diff --git a/core/java/android/service/settings/preferences/MetadataResult.java b/core/java/android/service/settings/preferences/MetadataResult.java index 6a65dcc9c757..e62fa8f38c93 100644 --- a/core/java/android/service/settings/preferences/MetadataResult.java +++ b/core/java/android/service/settings/preferences/MetadataResult.java @@ -131,6 +131,7 @@ public final class MetadataResult implements Parcelable { /** * Builder to construct {@link MetadataResult}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { @ResultCode private final int mResultCode; diff --git a/core/java/android/service/settings/preferences/SetValueRequest.java b/core/java/android/service/settings/preferences/SetValueRequest.java index f7600aecdfaf..77581d9deffe 100644 --- a/core/java/android/service/settings/preferences/SetValueRequest.java +++ b/core/java/android/service/settings/preferences/SetValueRequest.java @@ -123,6 +123,7 @@ public final class SetValueRequest implements Parcelable { /** * Builder to construct {@link SetValueRequest}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { private final String mScreenKey; private final String mPreferenceKey; diff --git a/core/java/android/service/settings/preferences/SetValueResult.java b/core/java/android/service/settings/preferences/SetValueResult.java index cb1776abd3bc..513f7a7d5bcc 100644 --- a/core/java/android/service/settings/preferences/SetValueResult.java +++ b/core/java/android/service/settings/preferences/SetValueResult.java @@ -156,6 +156,7 @@ public final class SetValueResult implements Parcelable { /** * Builder to construct {@link SetValueResult}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { @ResultCode private final int mResultCode; diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java index ea7d4a675713..30631f2fd71d 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java @@ -102,6 +102,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** * Returns the breadcrumbs (navigation context) of Preference. * <p>May be empty. + * @hide restrict to platform; may be opened wider in the future */ @NonNull public List<String> getBreadcrumbs() { @@ -189,33 +190,32 @@ public final class SettingsPreferenceMetadata implements Parcelable { @IntDef(value = { NO_SENSITIVITY, EXPECT_POST_CONFIRMATION, - EXPECT_PRE_CONFIRMATION, + DEEPLINK_ONLY, NO_DIRECT_ACCESS, }) @Retention(RetentionPolicy.SOURCE) public @interface WriteSensitivity {} /** - * Indicates preference is not sensitive. + * Indicates preference is not write-sensitive. * <p>Its value is writable without explicit consent, assuming all necessary permissions are * granted. */ public static final int NO_SENSITIVITY = 0; /** - * Indicates preference is mildly sensitive. + * Indicates preference is mildly write-sensitive. * <p>In addition to necessary permissions, after writing its value the user should be * given the option to revert back. */ public static final int EXPECT_POST_CONFIRMATION = 1; /** - * Indicates preference is sensitive. - * <p>In addition to necessary permissions, the user should be prompted for confirmation prior - * to making a change. Otherwise it is suggested to provide a deeplink to the Preference's page - * instead, accessible via {@link #getLaunchIntent}. + * Indicates preference is write-sensitive. + * <p>This preference cannot be changed through this API; instead a deeplink to the Preference's + * page should be used instead, accessible via {@link #getLaunchIntent}. */ - public static final int EXPECT_PRE_CONFIRMATION = 2; + public static final int DEEPLINK_ONLY = 2; /** - * Indicates preference is highly sensitivity and carries significant user-risk. + * Indicates preference is highly write-sensitivity and carries significant user-risk. * <p>This Preference cannot be changed through this API and no direct deeplink is available. * Other Metadata is still available. */ @@ -303,6 +303,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** * Builder to construct {@link SettingsPreferenceMetadata}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { private final String mScreenKey; private final String mKey; @@ -355,6 +356,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** * Sets the preference breadcrumbs (navigation context). + * @hide */ @NonNull public Builder setBreadcrumbs(@NonNull List<String> breadcrumbs) { diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java index 08826ca9776b..eea93b321e47 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java @@ -170,6 +170,7 @@ public final class SettingsPreferenceValue implements Parcelable { /** * Builder to construct {@link SettingsPreferenceValue}. */ + @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public static final class Builder { @Type private final int mType; diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig index fb1bd1703ce6..6116d599baa0 100644 --- a/core/java/android/tracing/flags.aconfig +++ b/core/java/android/tracing/flags.aconfig @@ -70,3 +70,11 @@ flag { is_fixed_read_only: true bug: "352538294" } + +flag { + name: "system_server_large_perfetto_shmem_buffer" + namespace: "windowing_tools" + description: "Large perfetto shmem buffer" + is_fixed_read_only: true + bug: "382369925" +} diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 089b5c256b6e..6c50b5f945a5 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.flags.Flags.bufferStuffingRecovery; import static android.view.flags.Flags.FLAG_EXPECTED_PRESENTATION_TIME_API; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; @@ -965,22 +966,24 @@ public final class Choreographer { // Evaluate if buffer stuffing recovery needs to start or end, and // what actions need to be taken for recovery. - switch (updateBufferStuffingState(frameTimeNanos, vsyncEventData)) { - case NONE: - // Without buffer stuffing recovery, offsetFrameTimeNanos is - // synonymous with frameTimeNanos. - break; - case OFFSET: - // Add animation offset. Used to update frame timeline with - // offset before jitter is calculated. - offsetFrameTimeNanos = frameTimeNanos - frameIntervalNanos; - break; - case DELAY_FRAME: - // Intentional frame delay to help reduce queued buffer count. - scheduleVsyncLocked(); - return; - default: - break; + if (bufferStuffingRecovery()) { + switch (updateBufferStuffingState(frameTimeNanos, vsyncEventData)) { + case NONE: + // Without buffer stuffing recovery, offsetFrameTimeNanos is + // synonymous with frameTimeNanos. + break; + case OFFSET: + // Add animation offset. Used to update frame timeline with + // offset before jitter is calculated. + offsetFrameTimeNanos = frameTimeNanos - frameIntervalNanos; + break; + case DELAY_FRAME: + // Intentional frame delay to help reduce queued buffer count. + scheduleVsyncLocked(); + return; + default: + break; + } } try { diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 0c8a0d60a96a..ca0959af3ff8 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1597,7 +1597,9 @@ public final class Display { // Although we only care about the HDR/SDR ratio changing, that can also come in the // form of the larger DISPLAY_CHANGED event mGlobal.registerDisplayListener(toRegister, executor, - DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE | DisplayManagerGlobal .INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED, ActivityThread.currentPackageName()); diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ba098eb53246..e75b1b0bd17a 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -447,7 +447,18 @@ public final class DisplayInfo implements Parcelable { } public boolean equals(DisplayInfo other) { - return other != null + return equals(other, /* compareRefreshRate */ true); + } + + /** + * Compares if the two DisplayInfo objects are equal or not + * @param other The other DisplayInfo against which the comparison is to be done + * @param compareRefreshRate Indicates if the refresh rate is also to be considered in + * comparison + * @return + */ + public boolean equals(DisplayInfo other, boolean compareRefreshRate) { + boolean isEqualWithoutRefreshRate = other != null && layerStack == other.layerStack && flags == other.flags && type == other.type @@ -466,7 +477,6 @@ public final class DisplayInfo implements Parcelable { && logicalHeight == other.logicalHeight && Objects.equals(displayCutout, other.displayCutout) && rotation == other.rotation - && modeId == other.modeId && hasArrSupport == other.hasArrSupport && Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate) && Arrays.equals(supportedRefreshRates, other.supportedRefreshRates) @@ -490,7 +500,6 @@ public final class DisplayInfo implements Parcelable { && ownerUid == other.ownerUid && Objects.equals(ownerPackageName, other.ownerPackageName) && removeMode == other.removeMode - && getRefreshRate() == other.getRefreshRate() && brightnessMinimum == other.brightnessMinimum && brightnessMaximum == other.brightnessMaximum && brightnessDefault == other.brightnessDefault @@ -504,6 +513,13 @@ public final class DisplayInfo implements Parcelable { && Objects.equals( thermalBrightnessThrottlingDataId, other.thermalBrightnessThrottlingDataId) && canHostTasks == other.canHostTasks; + + if (compareRefreshRate) { + return isEqualWithoutRefreshRate + && (getRefreshRate() == other.getRefreshRate()) + && (modeId == other.modeId); + } + return isEqualWithoutRefreshRate; } @Override diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index a8d4e2d2c70a..48dfdd4a95f4 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -16,6 +16,9 @@ package android.view; + +import static com.android.hardware.input.Flags.removeFallbackModifiers; + import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -458,7 +461,15 @@ public class KeyCharacterMap implements Parcelable { FallbackAction action = FallbackAction.obtain(); metaState = KeyEvent.normalizeMetaState(metaState); if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) { - action.metaState = KeyEvent.normalizeMetaState(action.metaState); + if (removeFallbackModifiers()) { + // Strip all modifiers. This is safe to do since only exact keyCode + metaState + // modifiers will trigger a fallback. + // E.g. Ctrl + Space -> language_switch (fallback generated) + // Ctrl + Alt + Space -> Ctrl + Alt + Space (no fallback generated) + action.metaState = 0; + } else { + action.metaState = KeyEvent.normalizeMetaState(action.metaState); + } return action; } action.recycle(); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 6e6e87bb9403..4fc1cfc0ca82 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -206,7 +206,8 @@ public class Surface implements Parcelable { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"}, value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, - FRAME_RATE_COMPATIBILITY_GTE}) + FRAME_RATE_COMPATIBILITY_AT_LEAST, FRAME_RATE_COMPATIBILITY_EXACT, + FRAME_RATE_COMPATIBILITY_MIN}) public @interface FrameRateCompatibility {} // From native_window.h. Keep these in sync. @@ -219,7 +220,7 @@ public class Surface implements Parcelable { * In Android version {@link Build.VERSION_CODES#BAKLAVA} and above, use * {@link FRAME_RATE_COMPATIBILITY_DEFAULT} for game content. * For other cases, see {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} and - * {@link FRAME_RATE_COMPATIBILITY_GTE}. + * {@link FRAME_RATE_COMPATIBILITY_AT_LEAST}. */ public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; @@ -234,7 +235,7 @@ public class Surface implements Parcelable { public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; /** - * The surface requests a frame rate that is greater than or equal to the specified frame rate. + * The surface requests a frame rate that is at least the specified frame rate. * This value should be used for UIs, animations, scrolling and fling, and anything that is not * a game or video. * @@ -242,7 +243,7 @@ public class Surface implements Parcelable { * {@link FRAME_RATE_COMPATIBILITY_DEFAULT}. */ @FlaggedApi(com.android.graphics.surfaceflinger.flags.Flags.FLAG_ARR_SETFRAMERATE_GTE_ENUM) - public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; + public static final int FRAME_RATE_COMPATIBILITY_AT_LEAST = 2; /** * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index f22505b80948..833f2d98554e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -22,7 +22,6 @@ import static android.graphics.Matrix.MSKEW_X; import static android.graphics.Matrix.MSKEW_Y; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; -import static android.view.flags.Flags.bufferStuffingRecovery; import static android.view.SurfaceControlProto.HASH_CODE; import static android.view.SurfaceControlProto.LAYER_ID; import static android.view.SurfaceControlProto.NAME; @@ -5118,11 +5117,9 @@ public final class SurfaceControl implements Parcelable { */ @NonNull public Transaction setRecoverableFromBufferStuffing(@NonNull SurfaceControl sc) { - if (bufferStuffingRecovery()) { - checkPreconditions(sc); - nativeSetFlags(mNativeObject, sc.mNativeObject, RECOVERABLE_FROM_BUFFER_STUFFING, - RECOVERABLE_FROM_BUFFER_STUFFING); - } + checkPreconditions(sc); + nativeSetFlags(mNativeObject, sc.mNativeObject, RECOVERABLE_FROM_BUFFER_STUFFING, + RECOVERABLE_FROM_BUFFER_STUFFING); return this; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d13f0e21bf80..d88b6d642ee6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -27,7 +27,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; -import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS; @@ -34199,7 +34199,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, && viewRootImpl.shouldCheckFrameRateCategory() && parent instanceof View && ((View) parent).getFrameContentVelocity() <= 0 - && !isInputMethodWindowType) { + && !isInputMethodWindowType + && viewRootImpl.getFrameRateCompatibility() != FRAME_RATE_COMPATIBILITY_AT_LEAST) { return FRAME_RATE_CATEGORY_HIGH_HINT | FRAME_RATE_CATEGORY_REASON_BOOST; } @@ -34251,7 +34252,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; frameRateToSet = frameRate; } else { - compatibility = FRAME_RATE_COMPATIBILITY_GTE; + compatibility = FRAME_RATE_COMPATIBILITY_AT_LEAST; frameRateToSet = velocityFrameRate; } viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1d27574eca8c..16cdb64f62cc 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -38,7 +38,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; -import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST; import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED; import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT; @@ -1828,7 +1828,8 @@ public final class ViewRootImpl implements ViewParent, | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED : DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; DisplayManagerGlobal .getInstance() @@ -13271,7 +13272,7 @@ public final class ViewRootImpl implements ViewParent, * We set category to HIGH if the maximum frame rate is greater than 60. * Otherwise, we set category to NORMAL. * - * Use FRAME_RATE_COMPATIBILITY_GTE for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE + * Use FRAME_RATE_COMPATIBILITY_AT_LEAST for velocity and FRAME_RATE_COMPATIBILITY_FIXED_SOURCE * for TextureView video play and user requested frame rate. * * @param frameRate the preferred frame rate of a View @@ -13282,7 +13283,7 @@ public final class ViewRootImpl implements ViewParent, if (frameRate <= 0) { return; } - if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE && !mIsPressedGesture) { + if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_AT_LEAST && !mIsPressedGesture) { mIsTouchBoosting = false; mIsFrameRateBoosting = false; if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) { diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 70c899f1efc7..8baa55f8e377 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -142,6 +142,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override + void internalNotifySessionFlushEvent(int sessionId) { + getMainCaptureSession().internalNotifySessionFlushEvent(sessionId); + } + + @Override boolean isContentCaptureEnabled() { return getMainCaptureSession().isContentCaptureEnabled(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index db4ac5de0b49..efd39163c3b8 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -18,7 +18,9 @@ package android.view.contentcapture; import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString; import static android.view.contentcapture.ContentCaptureManager.DEBUG; import static android.view.contentcapture.ContentCaptureManager.NO_SESSION_ID; +import static android.view.contentcapture.flags.Flags.FLAG_CCAPI_BAKLAVA_ENABLED; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -137,6 +139,12 @@ public final class ContentCaptureEvent implements Parcelable { */ public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10; + /** + * Called to flush a semantics meaningful view changes status to Intelligence Service. + */ + @FlaggedApi(FLAG_CCAPI_BAKLAVA_ENABLED) + public static final int TYPE_SESSION_FLUSH = 11; + /** @hide */ @IntDef(prefix = { "TYPE_" }, value = { TYPE_VIEW_APPEARED, @@ -149,6 +157,7 @@ public final class ContentCaptureEvent implements Parcelable { TYPE_SESSION_RESUMED, TYPE_VIEW_INSETS_CHANGED, TYPE_WINDOW_BOUNDS_CHANGED, + TYPE_SESSION_FLUSH, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType{} @@ -697,6 +706,8 @@ public final class ContentCaptureEvent implements Parcelable { return "VIEW_INSETS_CHANGED"; case TYPE_WINDOW_BOUNDS_CHANGED: return "TYPE_WINDOW_BOUNDS_CHANGED"; + case TYPE_SESSION_FLUSH: + return "TYPE_SESSION_FLUSH"; default: return "UKNOWN_TYPE: " + type; } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 0ca36ba28e3a..9aeec20ec9b7 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -19,8 +19,10 @@ import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import static android.view.contentcapture.ContentCaptureManager.NO_SESSION_ID; +import static android.view.contentcapture.flags.Flags.FLAG_CCAPI_BAKLAVA_ENABLED; import android.annotation.CallSuper; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -548,6 +550,35 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets); + /** + * Flushes an internal buffer of UI events and signals System Intelligence (SI) that a + * semantically meaningful state has been reached. SI uses this signal to potentially + * rebuild the view hierarchy and understand the current state of the UI. + * + * <p>UI events are often batched together for performance reasons. A semantic batch + * represents a series of events that, when applied sequentially, result in a + * meaningful and complete UI state. + * + * <p>It is crucial to call {@code flush()} after completing a semantic batch to ensure + * SI can accurately reconstruct the view hierarchy. + * + * <p><b>Premature Flushing:</b> Calling {@code flush()} within a semantic batch may + * lead to SI failing to rebuild the view hierarchy correctly. This could manifest as + * incorrect ordering of sibling nodes. + * + * <p><b>Delayed Flushing:</b> While not immediately flushing after a semantic batch is + * generally safe, it's recommended to do so as soon as possible. In the worst-case + * scenario where a {@code flush()} is never called, SI will attempt to process the + * events after a short delay based on view appearance and disappearance events. + */ + @FlaggedApi(FLAG_CCAPI_BAKLAVA_ENABLED) + public void flush() { + internalNotifySessionFlushEvent(mId); + } + + /** @hide */ + abstract void internalNotifySessionFlushEvent(int sessionId); + /** @hide */ public void notifyViewTreeEvent(boolean started) { internalNotifyViewTreeEvent(mId, started); diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index eb827dd5258d..2fb78c038ca2 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -17,6 +17,7 @@ package android.view.contentcapture; import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FLUSH; import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED; @@ -623,6 +624,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @Override 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)); } @@ -890,6 +893,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { enqueueEvent(event); } + @Override + void internalNotifySessionFlushEvent(int sessionId) { + final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_SESSION_FLUSH); + enqueueEvent(event, FORCE_FLUSH); + } + private List<ContentCaptureEvent> clearBufferEvents() { final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>(); ContentCaptureEvent event; diff --git a/core/java/android/view/contentcapture/OWNERS b/core/java/android/view/contentcapture/OWNERS index 9ac273f515e7..30f4cae4bf19 100644 --- a/core/java/android/view/contentcapture/OWNERS +++ b/core/java/android/view/contentcapture/OWNERS @@ -1,4 +1,5 @@ # Bug component: 544200 -hackz@google.com -shivanker@google.com +dariofreni@google.com +klikli@google.com +shikhamalhotra@google.com 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 416a877d87ab..f709ed7f57cd 100644 --- a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig +++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig @@ -7,3 +7,10 @@ flag { description: "Feature flag for running content capture tasks on background thread" bug: "309411951" } + +flag { + name: "ccapi_baklava_enabled" + namespace: "machine_learning" + description: "Feature flag for baklava content capture API" + bug: "380381249" +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index f82e5f984f5d..d5f471edfdd2 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -938,27 +938,6 @@ public final class InputMethodManager { synchronized (mH) { if (mCurRootView == viewRootImpl) { mCurRootViewWindowFocused = false; - - if (Flags.refactorInsetsController() && mCurRootView != null) { - final int softInputMode = mCurRootView.mWindowAttributes.softInputMode; - final int state = - softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; - if (state == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) { - // when losing focus (e.g., by going to another window), we reset the - // requestedVisibleTypes of WindowInsetsController by hiding the IME - final var statsToken = ImeTracker.forLogging().onStart( - ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, - SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS, - false /* fromUser */); - if (DEBUG) { - Log.d(TAG, "onWindowLostFocus, hiding IME because " - + "of STATE_ALWAYS_HIDDEN"); - } - mCurRootView.getInsetsController().hide(WindowInsets.Type.ime(), - false /* fromIme */, statsToken); - } - } - clearCurRootViewIfNeeded(); } } @@ -1012,6 +991,26 @@ public final class InputMethodManager { @GuardedBy("mH") private void setCurrentRootViewLocked(ViewRootImpl rootView) { final boolean wasEmpty = mCurRootView == null; + if (Flags.refactorInsetsController() && !wasEmpty && mCurRootView != rootView) { + final int softInputMode = mCurRootView.mWindowAttributes.softInputMode; + final int state = + softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; + if (state == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) { + // when losing input focus (e.g., by going to another window), we reset the + // requestedVisibleTypes of WindowInsetsController by hiding the IME + final var statsToken = ImeTracker.forLogging().onStart( + ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, + SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS, + false /* fromUser */); + if (DEBUG) { + Log.d(TAG, "setCurrentRootViewLocked, hiding IME because " + + "of STATE_ALWAYS_HIDDEN"); + } + mCurRootView.getInsetsController().hide(WindowInsets.Type.ime(), + false /* fromIme */, statsToken); + } + } + mImeDispatcher.switchRootView(mCurRootView, rootView); mCurRootView = rootView; if (wasEmpty && mCurRootView != null) { diff --git a/core/java/android/window/SnapshotDrawerUtils.java b/core/java/android/window/SnapshotDrawerUtils.java index 5397da11eb36..435c8c79122f 100644 --- a/core/java/android/window/SnapshotDrawerUtils.java +++ b/core/java/android/window/SnapshotDrawerUtils.java @@ -44,20 +44,16 @@ import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_AT import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; import android.content.Context; import android.graphics.Canvas; -import android.graphics.GraphicBuffer; import android.graphics.Paint; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.util.Log; -import android.view.InsetsState; import android.view.SurfaceControl; import android.view.ViewGroup; import android.view.WindowInsets; @@ -66,7 +62,6 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; -import com.android.window.flags.Flags; /** * Utils class to help draw a snapshot on a surface. @@ -103,8 +98,6 @@ public class SnapshotDrawerUtils { | FLAG_SECURE | FLAG_DIM_BEHIND; - private static final Paint sBackgroundPaint = new Paint(); - /** * The internal object to hold the surface and drawing on it. */ @@ -115,54 +108,29 @@ public class SnapshotDrawerUtils { private final TaskSnapshot mSnapshot; private final CharSequence mTitle; - private SystemBarBackgroundPainter mSystemBarBackgroundPainter; - private final Rect mFrame = new Rect(); - private final Rect mSystemBarInsets = new Rect(); private final int mSnapshotW; private final int mSnapshotH; - private boolean mSizeMismatch; + private final int mContainerW; + private final int mContainerH; public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot, - CharSequence title) { + Rect windowBounds, CharSequence title) { mRootSurface = rootSurface; mSnapshot = snapshot; mTitle = title; final HardwareBuffer hwBuffer = snapshot.getHardwareBuffer(); mSnapshotW = hwBuffer.getWidth(); mSnapshotH = hwBuffer.getHeight(); + mContainerW = windowBounds.width(); + mContainerH = windowBounds.height(); } - /** - * Initiate system bar painter to draw the system bar background. - */ - @VisibleForTesting - public void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags, - int appearance, ActivityManager.TaskDescription taskDescription, - @WindowInsets.Type.InsetsType int requestedVisibleTypes) { - mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags, - windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes); - int backgroundColor = taskDescription.getBackgroundColor(); - sBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE); - } - - /** - * Set frame size that the snapshot should fill. It is the bounds of a task or activity. - */ - @VisibleForTesting - public void setFrames(Rect frame, Rect systemBarInsets) { - mFrame.set(frame); + private void drawSnapshot(boolean releaseAfterDraw) { final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); - mSizeMismatch = (mFrame.width() != mSnapshotW || mFrame.height() != mSnapshotH) + final boolean sizeMismatch = mContainerW != mSnapshotW || mContainerH != mSnapshotH || letterboxInsets.left != 0 || letterboxInsets.top != 0; - if (!Flags.drawSnapshotAspectRatioMatch() && systemBarInsets != null) { - mSystemBarInsets.set(systemBarInsets); - mSystemBarBackgroundPainter.setInsets(systemBarInsets); - } - } - - private void drawSnapshot(boolean releaseAfterDraw) { - Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch); - if (mSizeMismatch) { + Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + sizeMismatch); + if (sizeMismatch) { // The dimensions of the buffer and the window don't match, so attaching the buffer // will fail. Better create a child window with the exact dimensions and fill the // parent window with the background color! @@ -189,11 +157,6 @@ public class SnapshotDrawerUtils { private void drawSizeMismatchSnapshot() { final HardwareBuffer buffer = mSnapshot.getHardwareBuffer(); - // We consider nearly matched dimensions as there can be rounding errors and the user - // won't notice very minute differences from scaling one dimension more than the other - boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH) - && !Flags.drawSnapshotAspectRatioMatch(); - // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder() .setName(mTitle + " - task-snapshot-surface") @@ -203,166 +166,28 @@ public class SnapshotDrawerUtils { .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot") .build(); - final Rect frame; final Rect letterboxInsets = mSnapshot.getLetterboxInsets(); float offsetX = letterboxInsets.left; float offsetY = letterboxInsets.top; // We can just show the surface here as it will still be hidden as the parent is // still hidden. mTransaction.show(childSurfaceControl); - if (aspectRatioMismatch) { - Rect crop = null; - if (letterboxInsets.left != 0 || letterboxInsets.top != 0 - || letterboxInsets.right != 0 || letterboxInsets.bottom != 0) { - // Clip off letterbox. - crop = calculateSnapshotCrop(letterboxInsets); - // If the snapshot can cover the frame, then no need to draw background. - aspectRatioMismatch = !isAspectRatioMatch(mFrame, crop); - } - // if letterbox doesn't match window frame, try crop by content insets - if (aspectRatioMismatch) { - // Clip off ugly navigation bar. - final Rect contentInsets = mSnapshot.getContentInsets(); - crop = calculateSnapshotCrop(contentInsets); - offsetX = contentInsets.left; - offsetY = contentInsets.top; - } - frame = calculateSnapshotFrame(crop); - mTransaction.setCrop(childSurfaceControl, crop); - } else { - frame = null; - } // Align the snapshot with content area. if (offsetX != 0f || offsetY != 0f) { mTransaction.setPosition(childSurfaceControl, - -offsetX * mFrame.width() / mSnapshot.getTaskSize().x, - -offsetY * mFrame.height() / mSnapshot.getTaskSize().y); + -offsetX * mContainerW / mSnapshot.getTaskSize().x, + -offsetY * mContainerH / mSnapshot.getTaskSize().y); } // Scale the mismatch dimensions to fill the target frame. - final float scaleX = (float) mFrame.width() / mSnapshotW; - final float scaleY = (float) mFrame.height() / mSnapshotH; + final float scaleX = (float) mContainerW / mSnapshotW; + final float scaleY = (float) mContainerH / mSnapshotH; mTransaction.setScale(childSurfaceControl, scaleX, scaleY); mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace()); mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer()); - - if (aspectRatioMismatch) { - GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(), - PixelFormat.RGBA_8888, - GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER - | GraphicBuffer.USAGE_SW_WRITE_RARELY); - final Canvas c = background != null ? background.lockCanvas() : null; - if (c == null) { - Log.e(TAG, "Unable to draw snapshot: failed to allocate graphic buffer for " - + mTitle); - mTransaction.clear(); - childSurfaceControl.release(); - return; - } - drawBackgroundAndBars(c, frame); - background.unlockCanvasAndPost(c); - mTransaction.setBuffer(mRootSurface, - HardwareBuffer.createFromGraphicBuffer(background)); - } mTransaction.apply(); childSurfaceControl.release(); } - - /** - * Calculates the snapshot crop in snapshot coordinate space. - * @param insets Content insets or Letterbox insets - * @return crop rect in snapshot coordinate space. - */ - @VisibleForTesting - public Rect calculateSnapshotCrop(@NonNull Rect insets) { - final Rect rect = new Rect(); - rect.set(0, 0, mSnapshotW, mSnapshotH); - - final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; - final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; - - // Let's remove all system decorations except the status bar, but only if the task is at - // the very top of the screen. - final boolean isTop = mFrame.top == 0; - rect.inset((int) (insets.left * scaleX), - isTop ? 0 : (int) (insets.top * scaleY), - (int) (insets.right * scaleX), - (int) (insets.bottom * scaleY)); - return rect; - } - - /** - * Calculates the snapshot frame in window coordinate space from crop. - * - * @param crop rect that is in snapshot coordinate space. - */ - @VisibleForTesting - public Rect calculateSnapshotFrame(Rect crop) { - final float scaleX = (float) mSnapshotW / mSnapshot.getTaskSize().x; - final float scaleY = (float) mSnapshotH / mSnapshot.getTaskSize().y; - - // Rescale the frame from snapshot to window coordinate space - final Rect frame = new Rect(0, 0, - (int) (crop.width() / scaleX + 0.5f), - (int) (crop.height() / scaleY + 0.5f) - ); - - // However, we also need to make space for the navigation bar on the left side. - frame.offset(mSystemBarInsets.left, 0); - return frame; - } - - /** - * Draw status bar and navigation bar background. - */ - @VisibleForTesting - public void drawBackgroundAndBars(Canvas c, Rect frame) { - final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight(); - final boolean fillHorizontally = c.getWidth() > frame.right; - final boolean fillVertically = c.getHeight() > frame.bottom; - if (fillHorizontally) { - c.drawRect(frame.right, alpha(mSystemBarBackgroundPainter.mStatusBarColor) == 0xFF - ? statusBarHeight : 0, c.getWidth(), fillVertically - ? frame.bottom : c.getHeight(), sBackgroundPaint); - } - if (fillVertically) { - c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), sBackgroundPaint); - } - mSystemBarBackgroundPainter.drawDecors(c, frame); - } - - /** - * Ask system bar background painter to draw status bar background. - */ - @VisibleForTesting - public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) { - mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame, - mSystemBarBackgroundPainter.getStatusBarColorViewHeight()); - } - - /** - * Ask system bar background painter to draw navigation bar background. - */ - @VisibleForTesting - public void drawNavigationBarBackground(Canvas c) { - mSystemBarBackgroundPainter.drawNavigationBarBackground(c); - } - } - - private static boolean isAspectRatioMatch(Rect frame, int w, int h) { - if (frame.isEmpty()) { - return false; - } - return Math.abs(((float) w / h) - ((float) frame.width() / frame.height())) <= 0.01f; - } - - private static boolean isAspectRatioMatch(Rect frame1, Rect frame2) { - if (frame1.isEmpty() || frame2.isEmpty()) { - return false; - } - return Math.abs( - ((float) frame2.width() / frame2.height()) - - ((float) frame1.width() / frame1.height())) <= 0.01f; } /** @@ -383,28 +208,15 @@ public class SnapshotDrawerUtils { /** * Help method to draw the snapshot on a surface. */ - public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp, + public static void drawSnapshotOnSurface(WindowManager.LayoutParams lp, SurfaceControl rootSurface, TaskSnapshot snapshot, - Rect windowBounds, InsetsState topWindowInsetsState, - boolean releaseAfterDraw) { + Rect windowBounds, boolean releaseAfterDraw) { if (windowBounds.isEmpty()) { Log.e(TAG, "Unable to draw snapshot on an empty windowBounds"); return; } final SnapshotSurface drawSurface = new SnapshotSurface( - rootSurface, snapshot, lp.getTitle()); - final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() - ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; - final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo; - final ActivityManager.TaskDescription taskDescription = - getOrCreateTaskDescription(runningTaskInfo); - Rect systemBarInsets = null; - if (!Flags.drawSnapshotAspectRatioMatch()) { - drawSurface.initiateSystemBarPainter(lp.flags, lp.privateFlags, - attrs.insetsFlags.appearance, taskDescription, info.requestedVisibleTypes); - systemBarInsets = getSystemBarInsets(windowBounds, topWindowInsetsState); - } - drawSurface.setFrames(windowBounds, systemBarInsets); + rootSurface, snapshot, windowBounds, lp.getTitle()); drawSurface.drawSnapshot(releaseAfterDraw); } @@ -414,10 +226,8 @@ public class SnapshotDrawerUtils { public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info, CharSequence title, @WindowManager.LayoutParams.WindowType int windowType, int pixelFormat, IBinder token) { - final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() - ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; - final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams; - if (attrs == null || mainWindowParams == null) { + final WindowManager.LayoutParams attrs = info.mainWindowLayoutParams; + if (attrs == null) { Log.w(TAG, "unable to create taskSnapshot surface "); return null; } @@ -427,9 +237,9 @@ public class SnapshotDrawerUtils { final int windowFlags = attrs.flags; final int windowPrivateFlags = attrs.privateFlags; - layoutParams.packageName = mainWindowParams.packageName; - layoutParams.windowAnimations = mainWindowParams.windowAnimations; - layoutParams.dimAmount = mainWindowParams.dimAmount; + layoutParams.packageName = attrs.packageName; + layoutParams.windowAnimations = attrs.windowAnimations; + layoutParams.dimAmount = attrs.dimAmount; layoutParams.type = windowType; layoutParams.format = pixelFormat; layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES) @@ -460,14 +270,6 @@ public class SnapshotDrawerUtils { return layoutParams; } - static Rect getSystemBarInsets(Rect frame, @Nullable InsetsState state) { - if (state == null) { - return new Rect(); - } - return state.calculateInsets(frame, WindowInsets.Type.systemBars(), - false /* ignoreVisibility */).toRect(); - } - /** * Helper class to draw the background of the system bars in regions the task snapshot isn't * filling the window. diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 72df343a2dbe..80ccbddbd1d9 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; -import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; @@ -100,20 +99,6 @@ public final class StartingWindowInfo implements Parcelable { public ActivityInfo targetActivityInfo; /** - * InsetsState of TopFullscreenOpaqueWindow - * @hide - */ - @Nullable - public InsetsState topOpaqueWindowInsetsState; - - /** - * LayoutParams of TopFullscreenOpaqueWindow - * @hide - */ - @Nullable - public WindowManager.LayoutParams topOpaqueWindowLayoutParams; - - /** * LayoutParams of MainWindow * @hide */ @@ -263,8 +248,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.writeToParcel(dest, flags); dest.writeTypedObject(targetActivityInfo, flags); dest.writeInt(startingWindowTypeParameter); - dest.writeTypedObject(topOpaqueWindowInsetsState, flags); - dest.writeTypedObject(topOpaqueWindowLayoutParams, flags); dest.writeTypedObject(mainWindowLayoutParams, flags); dest.writeInt(splashScreenThemeResId); dest.writeBoolean(isKeyguardOccluded); @@ -280,9 +263,6 @@ public final class StartingWindowInfo implements Parcelable { taskBounds.readFromParcel(source); targetActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); startingWindowTypeParameter = source.readInt(); - topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR); - topOpaqueWindowLayoutParams = source.readTypedObject( - WindowManager.LayoutParams.CREATOR); mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); splashScreenThemeResId = source.readInt(); isKeyguardOccluded = source.readBoolean(); @@ -302,8 +282,6 @@ public final class StartingWindowInfo implements Parcelable { + " topActivityType=" + taskInfo.topActivityType + " preferredStartingWindowType=" + Integer.toHexString(startingWindowTypeParameter) - + " insetsState=" + topOpaqueWindowInsetsState - + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams + " mainWindowLayoutParams=" + mainWindowLayoutParams + " splashScreenThemeResId " + Integer.toHexString(splashScreenThemeResId); } diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java index 1ec05b65861d..fcd7dfbb1769 100644 --- a/core/java/android/window/WindowTokenClientController.java +++ b/core/java/android/window/WindowTokenClientController.java @@ -35,6 +35,7 @@ import android.view.WindowManagerGlobal; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; /** * Singleton controller to manage the attached {@link WindowTokenClient}s, and to dispatch @@ -137,7 +138,9 @@ public class WindowTokenClientController { // is initialized later, the SystemUiContext will start reporting from // DisplayContent#registerSystemUiContext, and WindowTokenClientController can report // the Configuration to the correct client. - recordWindowContextToken(client); + if (Flags.trackSystemUiContextBeforeWms()) { + recordWindowContextToken(client); + } return false; } final WindowContextInfo info; @@ -145,6 +148,9 @@ public class WindowTokenClientController { info = wms.attachWindowContextToDisplayContent(mAppThread, client, displayId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + Log.e(TAG, "Failed attachToDisplayContent", e); + return false; } if (info == null) { return false; diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig index 801698caff0e..a42759e9e23f 100644 --- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -2,10 +2,10 @@ package: "com.android.window.flags" container: "system" flag { - name: "disable_thin_letterboxing_policy" + name: "ignore_aspect_ratio_restrictions_for_resizeable_freeform_activities" namespace: "large_screen_experiences_app_compat" - description: "Whether reachability is disabled in case of thin letterboxing" - bug: "341027847" + description: "If a resizeable activity enters freeform mode, ignore all aspect ratio constraints." + bug: "381866902" metadata { purpose: PURPOSE_BUGFIX } @@ -58,13 +58,6 @@ flag { } flag { - name: "user_min_aspect_ratio_app_default" - namespace: "large_screen_experiences_app_compat" - description: "Whether the API PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT is available" - bug: "310816437" -} - -flag { name: "allow_hide_scm_button" namespace: "large_screen_experiences_app_compat" description: "Whether we should allow hiding the size compat restart button" @@ -80,16 +73,6 @@ flag { } flag { - name: "immersive_app_repositioning" - namespace: "large_screen_experiences_app_compat" - description: "Fix immersive apps changing size when repositioning" - bug: "334076352" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "camera_compat_for_freeform" namespace: "large_screen_experiences_app_compat" description: "Whether to apply Camera Compat treatment to fixed-orientation apps in freeform windowing mode" @@ -162,4 +145,14 @@ flag { description: "Whether the API for forcing apps to be universal resizable on virtual display is available" bug: "372848702" is_exported: true +} + +flag { + name: "release_user_aspect_ratio_wm" + namespace: "large_screen_experiences_app_compat" + description: "Whether to release UserAspectRatioSettingsWindowManager when button is hidden" + bug: "385049711" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 30668a6c6b1d..c1ed51264e23 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -243,17 +243,6 @@ flag { } flag { - name: "draw_snapshot_aspect_ratio_match" - namespace: "windowing_frontend" - description: "The aspect ratio should always match when drawing snapshot" - bug: "341020277" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "system_ui_post_animation_end" namespace: "windowing_frontend" description: "Run AnimatorListener#onAnimationEnd on next frame for SystemUI" @@ -379,17 +368,6 @@ flag { } flag { - name: "disallow_app_progress_embedded_window" - namespace: "windowing_frontend" - description: "Pilfer pointers when app transfer input gesture to embedded window." - bug: "365504126" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "predictive_back_system_override_callback" namespace: "windowing_frontend" description: "Provide pre-make predictive back API extension" @@ -441,4 +419,15 @@ flag { description: "Support insets definition and calculation relative to task bounds." bug: "277292497" is_fixed_read_only: true +} + +flag { + name: "exclude_drawing_app_theme_snapshot_from_lock" + namespace: "windowing_frontend" + description: "Do not hold wm lock when drawing app theme snapshot." + is_fixed_read_only: true + bug: "373502791" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 5a092b8522db..abd93cfaf179 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -105,6 +105,13 @@ flag { flag { namespace: "windowing_sdk" + name: "activity_embedding_support_for_connected_displays" + description: "Enables activity embedding support for connected displays, including enabling AE optimization for Settings." + bug: "369438353" +} + +flag { + namespace: "windowing_sdk" name: "wlinfo_oncreate" description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()" bug: "337820752" @@ -138,3 +145,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "windowing_sdk" + name: "normalize_home_intent" + description: "To ensure home is started in correct intent" + bug: "378505461" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + namespace: "windowing_sdk" + name: "condense_configuration_change_for_simple_mode" + description: "Condense configuration change for simple mode" + bug: "356738240" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 2cfc680a3fe8..f01aa80fab4f 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -163,4 +163,5 @@ interface IAppOpsService { void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); + oneway void noteOperationsInBatch(in Map batchedNoteOps); } diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java index 542b6d00ca37..b4945e7fd2ec 100644 --- a/core/java/com/android/internal/app/ProcessMap.java +++ b/core/java/com/android/internal/app/ProcessMap.java @@ -28,6 +28,11 @@ public class ProcessMap<E> { if (uids == null) return null; return uids.get(uid); } + + public SparseArray<E> get(String name) { + SparseArray<E> uids = mMap.get(name); + return uids; + } public E put(String name, int uid, E value) { SparseArray<E> uids = mMap.get(name); diff --git a/core/java/com/android/internal/jank/DisplayResolutionTracker.java b/core/java/com/android/internal/jank/DisplayResolutionTracker.java index 0c2fd4bbd7ae..5d66b3c10197 100644 --- a/core/java/com/android/internal/jank/DisplayResolutionTracker.java +++ b/core/java/com/android/internal/jank/DisplayResolutionTracker.java @@ -148,8 +148,8 @@ public class DisplayResolutionTracker { public void registerDisplayListener(DisplayManager.DisplayListener listener) { manager.registerDisplayListener(listener, handler, DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal - .INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE, ActivityThread.currentPackageName()); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 3e2f30118b2a..f14e1f63cdf6 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -236,4 +236,7 @@ interface IStatusBarService /** Shows rear display educational dialog */ void showRearDisplayDialog(int currentBaseState); + + /** Unbundle a categorized notification */ + void unbundleNotification(String key); } diff --git a/core/java/com/android/internal/util/LATENCY_TRACKER_OWNERS b/core/java/com/android/internal/util/LATENCY_TRACKER_OWNERS index 77550002e3c6..3ed902f69342 100644 --- a/core/java/com/android/internal/util/LATENCY_TRACKER_OWNERS +++ b/core/java/com/android/internal/util/LATENCY_TRACKER_OWNERS @@ -1,3 +1,5 @@ # TODO(b/274465475): Migrate LatencyTracker testing to its own module marcinoc@google.com ilkos@google.com +jjaggi@google.com +nicomazz@google.com diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 9bd52372e6c4..39ddea614ee4 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -25,6 +25,8 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static android.security.Flags.reportPrimaryAuthAttempts; import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth; +import static com.android.internal.widget.flags.Flags.hideLastCharWithPhysicalInput; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -42,6 +44,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.hardware.input.InputManagerGlobal; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -59,6 +62,7 @@ import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; +import android.view.InputDevice; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; @@ -1097,12 +1101,20 @@ public class LockPatternUtils { return type == CREDENTIAL_TYPE_PATTERN; } + private boolean hasActivePointerDeviceAttached() { + return !getEnabledNonTouchInputDevices(InputDevice.SOURCE_CLASS_POINTER).isEmpty(); + } + /** * @return Whether the visible pattern is enabled. */ @UnsupportedAppUsage public boolean isVisiblePatternEnabled(int userId) { - return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, true, userId); + boolean defaultValue = true; + if (hideLastCharWithPhysicalInput()) { + defaultValue = !hasActivePointerDeviceAttached(); + } + return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, defaultValue, userId); } /** @@ -1116,11 +1128,39 @@ public class LockPatternUtils { return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null; } + private List<InputDevice> getEnabledNonTouchInputDevices(int source) { + final InputManagerGlobal inputManager = InputManagerGlobal.getInstance(); + final int[] inputIds = inputManager.getInputDeviceIds(); + List<InputDevice> matchingDevices = new ArrayList<InputDevice>(); + for (final int deviceId : inputIds) { + final InputDevice inputDevice = inputManager.getInputDevice(deviceId); + if (!inputDevice.isEnabled()) continue; + if (inputDevice.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) continue; + if (inputDevice.isVirtual()) continue; + if (!inputDevice.supportsSource(source)) continue; + matchingDevices.add(inputDevice); + } + return matchingDevices; + } + + private boolean hasPhysicalKeyboardActive() { + final List<InputDevice> keyboards = + getEnabledNonTouchInputDevices(InputDevice.SOURCE_KEYBOARD); + for (final InputDevice keyboard : keyboards) { + if (keyboard.isFullKeyboard()) return true; + } + return false; + } + /** * @return Whether enhanced pin privacy is enabled. */ public boolean isPinEnhancedPrivacyEnabled(int userId) { - return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, false, userId); + boolean defaultValue = false; + if (hideLastCharWithPhysicalInput()) { + defaultValue = hasPhysicalKeyboardActive(); + } + return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, defaultValue, userId); } /** diff --git a/core/jni/android_hardware_camera2_CameraDevice.cpp b/core/jni/android_hardware_camera2_CameraDevice.cpp index 493c7073416c..04cfed581750 100644 --- a/core/jni/android_hardware_camera2_CameraDevice.cpp +++ b/core/jni/android_hardware_camera2_CameraDevice.cpp @@ -30,6 +30,7 @@ #include <nativehelper/JNIHelp.h> #include "android_os_Parcel.h" #include "core_jni_helpers.h" +#include <android/binder_auto_utils.h> #include <android/binder_parcel_jni.h> #include <android/hardware/camera2/ICameraDeviceUser.h> #include <aidl/android/hardware/common/fmq/MQDescriptor.h> @@ -40,6 +41,7 @@ using namespace android; using ::android::AidlMessageQueue; +using ndk::ScopedAParcel; using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>; class FMQReader { @@ -75,15 +77,16 @@ extern "C" { static jlong CameraDevice_createFMQReader(JNIEnv *env, jclass thiz, jobject resultParcel) { - AParcel *resultAParcel = AParcel_fromJavaParcel(env, resultParcel); - if (resultAParcel == nullptr) { + ScopedAParcel sResultAParcel(AParcel_fromJavaParcel(env, resultParcel)); + if (sResultAParcel.get() == nullptr) { ALOGE("%s: Error creating result parcel", __FUNCTION__); return 0; } - AParcel_setDataPosition(resultAParcel, 0); + + AParcel_setDataPosition(sResultAParcel.get(), 0); MQDescriptor<int8_t, SynchronizedReadWrite> resultMQ; - if (resultMQ.readFromParcel(resultAParcel) != OK) { + if (resultMQ.readFromParcel(sResultAParcel.get()) != OK) { ALOGE("%s: read from result parcel failed", __FUNCTION__); return 0; } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 8003bb7d442b..639f5bff7614 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1706,6 +1706,10 @@ static jboolean android_os_BinderProxy_removeFrozenStateChangeCallback(JNIEnv* e return res; } +static jboolean android_os_BinderProxy_frozenStateChangeCallbackSupported(JNIEnv*, jclass*) { + return ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION); +} + static void BinderProxy_destroy(void* rawNativeData) { BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData; @@ -1750,6 +1754,8 @@ static const JNINativeMethod gBinderProxyMethods[] = { "(Landroid/os/IBinder$FrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback}, {"removeFrozenStateChangeCallbackNative", "(Landroid/os/IBinder$FrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback}, + {"isFrozenStateChangeCallbackSupportedNative", + "()Z", (void*)android_os_BinderProxy_frozenStateChangeCallbackSupported}, {"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer}, {"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension}, }; diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 7e9d62315ef1..c901ee1e3f8f 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -567,6 +567,8 @@ message SecureSettingsProto { // value. optional SettingProto rtt_calling_mode = 69 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto screen_off_udfps_enabled = 104 [ (android.privacy).dest = DEST_AUTOMATIC ]; + message Screensaver { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -744,5 +746,5 @@ message SecureSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 104; + // Next tag = 105; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e133ca48d0d7..ed05e6de0fe0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8780,6 +8780,20 @@ android:featureFlag="com.android.art.flags.executable_method_file_offsets" /> <!-- + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_UID_BASED_PROVIDER_LOOKUP) + Allows an app to resolve components (e.g ContentProviders) on behalf of + other UIDs + <p>Protection level: signature|privileged + @hide + --> + <permission + android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" + android:protectionLevel="signature|privileged" + android:featureFlag="android.content.pm.uid_based_provider_lookup" /> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> + + <!-- @TestApi Signature permission reserved for testing. This should never be used to gate any actual functionality. @@ -9164,15 +9178,6 @@ </intent-filter> </receiver> - <receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver" - android:exported="true" - android:permission="android.permission.UPDATE_CONFIG"> - <intent-filter> - <action android:name="android.intent.action.UPDATE_CT_LOGS" /> - <data android:scheme="content" android:host="*" android:mimeType="*/*" /> - </intent-filter> - </receiver> - <receiver android:name="com.android.server.updates.LangIdInstallReceiver" android:exported="true" android:permission="android.permission.UPDATE_CONFIG"> diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml index 76c810bdb2c1..e91e1115ac1c 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_base.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml @@ -157,39 +157,27 @@ android:maxDrawableHeight="@dimen/notification_right_icon_size" /> - <LinearLayout - android:id="@+id/notification_buttons_column" + <FrameLayout + android:id="@+id/expand_button_touch_container" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_alignParentEnd="true" - android:orientation="vertical" + android:minWidth="@dimen/notification_content_margin_end" > - <include layout="@layout/notification_close_button" - android:layout_width="@dimen/notification_close_button_size" - android:layout_height="@dimen/notification_close_button_size" - android:layout_gravity="end" - android:layout_marginEnd="20dp" - /> - - <FrameLayout - android:id="@+id/expand_button_touch_container" + <include layout="@layout/notification_expand_button" android:layout_width="wrap_content" - android:layout_height="0dp" - android:layout_weight="1" - android:minWidth="@dimen/notification_content_margin_end" - > - - <include layout="@layout/notification_expand_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|end" - /> - - </FrameLayout> + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|end" + /> - </LinearLayout> + </FrameLayout> </LinearLayout> + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="top|end" /> + </FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml index 2e0a7afc3cd1..2d367337bb6f 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_media.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml @@ -194,4 +194,11 @@ </FrameLayout> </LinearLayout> + + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="top|end" /> + </com.android.internal.widget.MediaNotificationView> diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml index f644adefda9d..fbecb8c30b9c 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml @@ -199,6 +199,12 @@ </LinearLayout> + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="top|end" /> + </com.android.internal.widget.NotificationMaxHeightFrameLayout> <LinearLayout diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml index fc727e1c72f5..2d30d8a8bbb6 100644 --- a/core/res/res/layout/notification_2025_template_header.xml +++ b/core/res/res/layout/notification_2025_template_header.xml @@ -60,7 +60,7 @@ android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_centerVertical="true" - android:layout_toStartOf="@id/notification_buttons_column" + android:layout_toStartOf="@id/expand_button" android:layout_alignWithParentIfMissing="true" android:clipChildren="false" android:gravity="center_vertical" @@ -81,28 +81,17 @@ android:focusable="false" /> - <LinearLayout - android:id="@+id/notification_buttons_column" + <include layout="@layout/notification_expand_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:orientation="vertical" - > - - <include layout="@layout/notification_close_button" - android:layout_width="@dimen/notification_close_button_size" - android:layout_height="@dimen/notification_close_button_size" - android:layout_gravity="end" - android:layout_marginEnd="20dp" - /> - - <include layout="@layout/notification_expand_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" - /> + android:layout_centerVertical="true" + android:layout_alignParentEnd="true" /> - </LinearLayout> + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" /> </NotificationHeaderView> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 3bb58a59945a..196f9ac14f3f 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1959,7 +1959,7 @@ <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Nit entre setmana"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Cap de setmana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Esdeveniment"</string> - <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Mentre dormo"</string> + <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Dormint"</string> <string name="zen_mode_implicit_name" msgid="177586786232302019">"No molestis (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string> <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Gestionat per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activat"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index ab3b66b666d7..e470f0e0a69c 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -421,7 +421,7 @@ <string name="permlab_runInBackground" msgid="541863968571682785">"exekutatu atzeko planoan"</string> <string name="permdesc_runInBackground" msgid="4344539472115495141">"Atzeko planoan exekuta liteke aplikazioa eta horrek bizkorrago agor lezake bateria."</string> <string name="permlab_useDataInBackground" msgid="783415807623038947">"erabili datuak atzeko planoan"</string> - <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Aplikazioak datuak erabil litzake atzeko planoan eta horrek datu-erabilera areago lezake."</string> + <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Datuak atzeko planoan erabil ditzake aplikazioak, eta baliteke horrek datu-erabilera handitzea."</string> <string name="permlab_schedule_exact_alarm" msgid="6683283918033029730">"antolatu ekintzak une zehatzetan gerta daitezen"</string> <string name="permdesc_schedule_exact_alarm" msgid="8198009212013211497">"Aplikazio honek ekintzak programa ditzake etorkizunean egin daitezen. Horrek esan nahi du gailua aktiboki erabiltzen ari ez zarenean ere exekuta daitekeela aplikazioa."</string> <string name="permlab_use_exact_alarm" msgid="348045139777131552">"antolatu alarmak edo gertaera-gogorarazpenak"</string> @@ -698,7 +698,7 @@ <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aurrera egiteko, erabili hatz-marka edo pantailaren blokeoa"</string> <string-array name="fingerprint_error_vendor"> </string-array> - <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Arazo bat izan da. Saiatu berriro."</string> + <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Arazoren bat izan da. Saiatu berriro."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string> <string name="device_unlock_notification_name" msgid="2632928999862915709">"Gailua desblokeatzea"</string> <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Probatu gailua desblokeatzeko beste modu bat"</string> @@ -759,7 +759,7 @@ <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string> <string-array name="face_error_vendor"> </string-array> - <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Arazo bat izan da. Saiatu berriro."</string> + <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Arazoren bat izan da. Saiatu berriro."</string> <string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string> <string name="permlab_readSyncSettings" msgid="6250532864893156277">"irakurri sinkronizazio-ezarpenak"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen dio aplikazioari. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 1f30da3e7305..b626194d46d3 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1049,7 +1049,7 @@ <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"За да го отклучите, најавете се со вашата сметка на Google."</string> <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Корисничко име (e-пошта)"</string> <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Лозинка"</string> - <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Најави се"</string> + <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Најавете се"</string> <string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Неважечко корисничко име или лозинка."</string> <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Го заборави своето корисничко име или лозинката?\nПосети"<b>"google.com/accounts/recovery"</b>"."</string> <string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Се проверува..."</string> @@ -1723,7 +1723,7 @@ <string name="kg_login_instructions" msgid="3619844310339066827">"За да го отклучите, најавете се со вашата сметка на Google."</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Корисничко име (е-пошта)"</string> <string name="kg_login_password_hint" msgid="3330530727273164402">"Лозинка"</string> - <string name="kg_login_submit_button" msgid="893611277617096870">"Најави се"</string> + <string name="kg_login_submit_button" msgid="893611277617096870">"Најавете се"</string> <string name="kg_login_invalid_input" msgid="8292367491901220210">"Неважечко корисничко име или лозинка."</string> <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Го заборави своето корисничко име или лозинката?\nПосети"<b>"google.com/accounts/recovery"</b>"."</string> <string name="kg_login_checking_password" msgid="4676010303243317253">"Сметката се проверува..."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e7e96f50297a..2cadf4b7ea15 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -288,7 +288,7 @@ <string name="global_action_settings" msgid="4671878836947494217">"Nastavitve"</string> <string name="global_action_assist" msgid="2517047220311505805">"Pomoč"</string> <string name="global_action_voice_assist" msgid="6655788068555086695">"Glas. pomočnik"</string> - <string name="global_action_lockdown" msgid="2475471405907902963">"Zakleni"</string> + <string name="global_action_lockdown" msgid="2475471405907902963">"Zaklep"</string> <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999 +"</string> <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"Odgovori"</string> <string name="notification_hidden_text" msgid="2835519769868187223">"Novo obvestilo"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index c2be30e11c11..2b97029a5e24 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1273,7 +1273,7 @@ <string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> పునరావృతంగా ఆపివేయబడుతోంది"</string> <string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> పునరావృతంగా ఆపివేయబడుతోంది"</string> <string name="aerr_restart" msgid="2789618625210505419">"యాప్ను మళ్లీ తెరువు"</string> - <string name="aerr_report" msgid="3095644466849299308">"ఫీడ్బ్యాక్ను పంపు"</string> + <string name="aerr_report" msgid="3095644466849299308">"ఫీడ్బ్యాక్ను పంపండి"</string> <string name="aerr_close" msgid="3398336821267021852">"మూసివేయండి"</string> <string name="aerr_mute" msgid="2304972923480211376">"పరికరం పునఃప్రారంభమయ్యే వరకు మ్యూట్ చేయి"</string> <string name="aerr_wait" msgid="3198677780474548217">"వేచి ఉండండి"</string> diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml index e28b6462bad7..e6295ea06177 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -100,4 +100,7 @@ <!-- Whether to enable scaling and fading animation to scrollviews while scrolling. P.S this is a change only intended for wear devices. --> <bool name="config_enableViewGroupScalingFading">true</bool> + + <!-- Allow the gesture to double tap the power button to trigger a target action. --> + <bool name="config_doubleTapPowerGestureEnabled">false</bool> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 565e28e0cc87..45a5d85a097d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2165,6 +2165,17 @@ config_enableGeofenceOverlay is false. --> <string name="config_geofenceProviderPackageName" translatable="false">@null</string> + <!-- Whether to enable GNSS assistance overlay which allows GnssAssistanceProvider to be + replaced by an app at run-time. When disabled, only the + config_gnssAssistanceProviderPackageName package will be searched for + GnssAssistanceProvider, otherwise any system package is eligible. Anyone who wants to + disable the overlay mechanism can set it to false. + --> + <bool name="config_enableGnssAssistanceOverlay" translatable="false">true</bool> + <!-- Package name providing GNSS assistance API support. Used only when + config_enableGnssAssistanceOverlay is false. --> + <string name="config_gnssAssistanceProviderPackageName" translatable="false">@null</string> + <!-- Whether to enable Hardware Activity-Recognition overlay which allows Hardware Activity-Recognition to be replaced by an app at run-time. When disabled, only the config_activityRecognitionHardwarePackageName package will be searched for diff --git a/core/res/res/values/config_watch.xml b/core/res/res/values/config_watch.xml index 629a343f1280..bcb1e0941b5a 100644 --- a/core/res/res/values/config_watch.xml +++ b/core/res/res/values/config_watch.xml @@ -15,8 +15,7 @@ --> <resources> - <!-- TODO(b/382103556): use predefined Material3 token --> <!-- For Wear Material3 --> - <dimen name="config_wearMaterial3_buttonCornerRadius">26dp</dimen> - <dimen name="config_wearMaterial3_bottomDialogCornerRadius">18dp</dimen> + <dimen name="config_wearMaterial3_buttonCornerRadius">@dimen/config_shapeCornerRadiusLarge</dimen> + <dimen name="config_wearMaterial3_bottomDialogCornerRadius">@dimen/config_shapeCornerRadiusMedium</dimen> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 73e06f6a2520..8195d38993c8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2040,6 +2040,7 @@ <java-symbol type="bool" name="config_useGnssHardwareProvider" /> <java-symbol type="bool" name="config_enableGeocoderOverlay" /> <java-symbol type="bool" name="config_enableGeofenceOverlay" /> + <java-symbol type="bool" name="config_enableGnssAssistanceOverlay" /> <java-symbol type="bool" name="config_enableNetworkLocationOverlay" /> <java-symbol type="bool" name="config_sf_limitedAlpha" /> <java-symbol type="bool" name="config_unplugTurnsOnScreen" /> @@ -2223,6 +2224,7 @@ <java-symbol type="string" name="config_gnssLocationProviderPackageName" /> <java-symbol type="string" name="config_geocoderProviderPackageName" /> <java-symbol type="string" name="config_geofenceProviderPackageName" /> + <java-symbol type="string" name="config_gnssAssistanceProviderPackageName" /> <java-symbol type="string" name="config_networkLocationProviderPackageName" /> <java-symbol type="string" name="config_wimaxManagerClassname" /> <java-symbol type="string" name="config_wimaxNativeLibLocation" /> diff --git a/core/tests/coretests/res/color/color_with_lstar.xml b/core/tests/coretests/res/color/color_with_lstar.xml index dcc3d6db1b0a..7762fc069ed5 100644 --- a/core/tests/coretests/res/color/color_with_lstar.xml +++ b/core/tests/coretests/res/color/color_with_lstar.xml @@ -16,5 +16,5 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="#ff0000" android:lStar="50" /> + <item android:color="@color/testcolor2" android:lStar="50" /> </selector> diff --git a/core/tests/coretests/res/values/colors.xml b/core/tests/coretests/res/values/colors.xml index 029aa0dd8eb6..f01af8421515 100644 --- a/core/tests/coretests/res/values/colors.xml +++ b/core/tests/coretests/res/values/colors.xml @@ -25,6 +25,5 @@ <drawable name="yellow">#ffffff00</drawable> <color name="testcolor1">#ff00ff00</color> <color name="testcolor2">#ffff0000</color> - <color name="testcolor3">#fff00000</color> <color name="failColor">#ff0000ff</color> </resources> diff --git a/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java index cf6266c756ce..931d64640ea2 100644 --- a/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java +++ b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java @@ -119,4 +119,15 @@ public class BackgroundStartPrivilegesTest { Arrays.asList(BSP_ALLOW_A, BSP_ALLOW_A, BSP_ALLOW_A, BSP_ALLOW_A))) .isEqualTo(BSP_ALLOW_A); } + + @Test + public void backgroundStartPrivilege_equals_works() { + assertThat(NONE).isEqualTo(NONE); + assertThat(ALLOW_BAL).isEqualTo(ALLOW_BAL); + assertThat(ALLOW_FGS).isEqualTo(ALLOW_FGS); + assertThat(BSP_ALLOW_A).isEqualTo(BSP_ALLOW_A); + assertThat(NONE).isNotEqualTo(ALLOW_BAL); + assertThat(ALLOW_FGS).isNotEqualTo(ALLOW_BAL); + assertThat(BSP_ALLOW_A).isNotEqualTo(BSP_ALLOW_B); + } } diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 9effeec23890..ca6ad6fae46e 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -105,6 +105,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.internal.util.ContrastColorUtil; +import com.android.internal.widget.NotificationProgressModel; import junit.framework.Assert; @@ -2414,7 +2415,7 @@ public class NotificationTest { @Test @EnableFlags(Flags.FLAG_API_RICH_ONGOING) - public void progressStyle_getProgressMax_nooSegments_returnsDefault() { + public void progressStyle_getProgressMax_noSegments_returnsDefault() { final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); progressStyle.setProgressSegments(Collections.emptyList()); assertThat(progressStyle.getProgressMax()).isEqualTo(100); @@ -2459,6 +2460,211 @@ public class NotificationTest { @Test @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_getProgressMax_onSegmentLimitExceeded_returnsSumOfSegmentLength() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + // limit is 10 for ProgressStyle + for (int i = 0; i < 30; i++) { + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(10)); + } + + // THEN + assertThat(progressStyle.getProgressMax()).isEqualTo(300); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_addProgressSegment_dropsInvalidSegments() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + // Segments should be a positive integer. + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(0)); + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(-1)); + + // THEN + assertThat(progressStyle.getProgressSegments()).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_setProgressSegment_dropsInvalidSegments() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + // Segments should be a positive integer. + progressStyle + .setProgressSegments(List.of(new Notification.ProgressStyle.Segment(0), + new Notification.ProgressStyle.Segment(-1))); + + // THEN + assertThat(progressStyle.getProgressSegments()).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_addProgressPoint_dropsNegativePoints() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + // Points should not be a negative integer. + progressStyle + .addProgressPoint(new Notification.ProgressStyle.Point(-1)) + .addProgressPoint(new Notification.ProgressStyle.Point(-100)); + + // THEN + assertThat(progressStyle.getProgressPoints()).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_setProgressPoint_dropsNegativePoints() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + // Points should not be a negative integer. + progressStyle + .setProgressPoints(List.of(new Notification.ProgressStyle.Point(-1), + new Notification.ProgressStyle.Point(-100))); + + // THEN + assertThat(progressStyle.getProgressPoints()).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_createProgressModel_ignoresPointsExceedingMax() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100)); + // Points should not larger than progress maximum. + progressStyle + .addProgressPoint(new Notification.ProgressStyle.Point(101)) + .addProgressPoint(new Notification.ProgressStyle.Point(500)); + + // THEN + assertThat(progressStyle.createProgressModel(Color.BLUE, Color.RED).getPoints()).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_createProgressModel_ignoresOverLimitPoints() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + progressStyle.addProgressSegment(new Notification.ProgressStyle.Segment(100)); + + // maximum 4 points are going to be rendered. + progressStyle + .addProgressPoint(new Notification.ProgressStyle.Point(0)) + .addProgressPoint(new Notification.ProgressStyle.Point(20)) + .addProgressPoint(new Notification.ProgressStyle.Point(150)) + .addProgressPoint(new Notification.ProgressStyle.Point(50)) + .addProgressPoint(new Notification.ProgressStyle.Point(70)) + .addProgressPoint(new Notification.ProgressStyle.Point(80)) + .addProgressPoint(new Notification.ProgressStyle.Point(90)) + .addProgressPoint(new Notification.ProgressStyle.Point(95)) + .addProgressPoint(new Notification.ProgressStyle.Point(100)); + final int backgroundColor = Color.RED; + final int defaultProgressColor = Color.BLUE; + final int expectedProgressColor = Notification.ProgressStyle.sanitizeProgressColor( + /* color = */Notification.COLOR_DEFAULT, + /* bg = */backgroundColor, + /* defaultColor = */defaultProgressColor); + + // THEN + assertThat(progressStyle.createProgressModel(defaultProgressColor, backgroundColor) + .getPoints()).isEqualTo( + List.of(new Notification.ProgressStyle.Point(0) + .setColor(expectedProgressColor), + new Notification.ProgressStyle.Point(20) + .setColor(expectedProgressColor), + new Notification.ProgressStyle.Point(50) + .setColor(expectedProgressColor), + new Notification.ProgressStyle.Point(70) + .setColor(expectedProgressColor) + ) + ); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_createProgressModel_mergeSegmentsOnOverflow() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + + for (int i = 0; i < 15; i++) { + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(10)); + } + + final NotificationProgressModel progressModel = progressStyle.createProgressModel( + Color.BLUE, Color.RED); + + // THEN + assertThat(progressModel.getSegments().size()).isEqualTo(1); + assertThat(progressModel.getProgressMax()).isEqualTo(150); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_createProgressModel_useSegmentColorWhenAllMatch() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + final int segmentColor = Color.YELLOW; + final int defaultProgressColor = Color.BLUE; + final int backgroundColor = Color.RED; + // contrast ensured color for segmentColor. + final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor( + /* color = */ segmentColor, + /* bg = */ backgroundColor, + /* defaultColor = */ defaultProgressColor); + + for (int i = 0; i < 15; i++) { + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(10) + .setColor(segmentColor)); + } + + final NotificationProgressModel progressModel = progressStyle.createProgressModel( + defaultProgressColor, backgroundColor); + + // THEN + assertThat(progressModel.getSegments()) + .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150) + .setColor(expectedSegmentColor))); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) + public void progressStyle_createProgressModel_useDefaultColorWhenAllNotMatch() { + // GIVEN + final Notification.ProgressStyle progressStyle = new Notification.ProgressStyle(); + final int defaultProgressColor = Color.BLUE; + final int backgroundColor = Color.RED; + // contrast ensured color for default progress color. + final int expectedSegmentColor = Notification.ProgressStyle.sanitizeProgressColor( + /* color = */ defaultProgressColor, + /* bg = */ backgroundColor, + /* defaultColor = */ defaultProgressColor); + + for (int i = 0; i < 15; i++) { + progressStyle + .addProgressSegment(new Notification.ProgressStyle.Segment(5) + .setColor(Color.BLUE)) + .addProgressSegment(new Notification.ProgressStyle.Segment(5) + .setColor(Color.CYAN)); + } + + final NotificationProgressModel progressModel = progressStyle.createProgressModel( + defaultProgressColor, backgroundColor); + + // THEN + assertThat(progressModel.getSegments()) + .isEqualTo(List.of(new Notification.ProgressStyle.Segment(150) + .setColor(expectedSegmentColor))); + } + + @Test + @EnableFlags(Flags.FLAG_API_RICH_ONGOING) public void progressStyle_indeterminate_defaultValueFalse() { final Notification.ProgressStyle progressStyle1 = new Notification.ProgressStyle(); diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java index 911b7ce22741..10a85bcbf488 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java @@ -120,7 +120,8 @@ public class ClientTransactionListenerControllerTest { doReturn(newDisplayInfo).when(mIDisplayManager).getDisplayInfo(123); mDisplayManager.registerDisplayListener(mListener, mHandler, - DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE, null /* packageName */); mController.onDisplayChanged(123); diff --git a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java index 564460e18294..84bdbe03df13 100644 --- a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java @@ -16,19 +16,27 @@ package android.graphics; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import android.os.ParcelFileDescriptor; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; -public class BitmapFactoryTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class BitmapFactoryTest { // tests that we can decode bitmaps from MemoryFiles @SmallTest + @Test public void testBitmapParcelFileDescriptor() throws Exception { Bitmap bitmap1 = Bitmap.createBitmap( new int[] { Color.BLUE }, 1, 1, Bitmap.Config.RGB_565); diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java index 2280cf1cccfa..0126d367eb20 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -16,19 +16,28 @@ package android.graphics; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import android.hardware.HardwareBuffer; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -public class BitmapTest extends TestCase { +@SmallTest +@RunWith(AndroidJUnit4.class) +public class BitmapTest { - @SmallTest + @Test public void testBasic() throws Exception { Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); @@ -63,7 +72,7 @@ public class BitmapTest extends TestCase { assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_8888); } - @SmallTest + @Test public void testMutability() throws Exception { Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); Bitmap bm2 = Bitmap.createBitmap(new int[100 * 200], 100, 200, @@ -82,7 +91,7 @@ public class BitmapTest extends TestCase { } } - @SmallTest + @Test public void testGetPixelsWithAlpha() throws Exception { int[] colors = new int[100]; for (int i = 0; i < 100; i++) { @@ -108,7 +117,7 @@ public class BitmapTest extends TestCase { } - @SmallTest + @Test public void testGetPixelsWithoutAlpha() throws Exception { int[] colors = new int[100]; for (int i = 0; i < 100; i++) { @@ -125,7 +134,7 @@ public class BitmapTest extends TestCase { } } - @SmallTest + @Test public void testSetPixelsWithAlpha() throws Exception { int[] colors = new int[100]; for (int i = 0; i < 100; i++) { @@ -151,7 +160,7 @@ public class BitmapTest extends TestCase { } } - @SmallTest + @Test public void testSetPixelsWithoutAlpha() throws Exception { int[] colors = new int[100]; for (int i = 0; i < 100; i++) { @@ -181,7 +190,7 @@ public class BitmapTest extends TestCase { return unpre; } - @SmallTest + @Test public void testSetPixelsWithNonOpaqueAlpha() throws Exception { int[] colors = new int[256]; for (int i = 0; i < 256; i++) { @@ -238,10 +247,13 @@ public class BitmapTest extends TestCase { } } - @SmallTest + private static final int GRAPHICS_USAGE = + GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SW_READ_OFTEN + | GraphicBuffer.USAGE_SW_WRITE_OFTEN; + + @Test public void testWrapHardwareBufferWithSrgbColorSpace() { - GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, - GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK); + GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, GRAPHICS_USAGE); Canvas canvas = buffer.lockCanvas(); canvas.drawColor(Color.YELLOW); buffer.unlockCanvasAndPost(canvas); @@ -252,10 +264,9 @@ public class BitmapTest extends TestCase { assertEquals(ColorSpace.get(ColorSpace.Named.SRGB), hardwareBitmap.getColorSpace()); } - @SmallTest + @Test public void testWrapHardwareBufferWithDisplayP3ColorSpace() { - GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, - GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK); + GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888, GRAPHICS_USAGE); Canvas canvas = buffer.lockCanvas(); canvas.drawColor(Color.YELLOW); buffer.unlockCanvasAndPost(canvas); @@ -267,7 +278,7 @@ public class BitmapTest extends TestCase { assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace()); } - @SmallTest + @Test public void testCopyWithDirectByteBuffer() { // Initialize Bitmap final int width = 2; @@ -305,7 +316,7 @@ public class BitmapTest extends TestCase { assertTrue(bm2.sameAs(bm1)); } - @SmallTest + @Test public void testCopyWithDirectShortBuffer() { // Initialize Bitmap final int width = 2; @@ -344,7 +355,7 @@ public class BitmapTest extends TestCase { assertTrue(bm2.sameAs(bm1)); } - @SmallTest + @Test public void testCopyWithDirectIntBuffer() { // Initialize Bitmap final int width = 2; @@ -383,7 +394,7 @@ public class BitmapTest extends TestCase { assertTrue(bm2.sameAs(bm1)); } - @SmallTest + @Test public void testCopyWithHeapByteBuffer() { // Initialize Bitmap final int width = 2; @@ -420,7 +431,7 @@ public class BitmapTest extends TestCase { assertTrue(bm2.sameAs(bm1)); } - @SmallTest + @Test public void testCopyWithHeapShortBuffer() { // Initialize Bitmap final int width = 2; @@ -457,7 +468,7 @@ public class BitmapTest extends TestCase { assertTrue(bm2.sameAs(bm1)); } - @SmallTest + @Test public void testCopyWithHeapIntBuffer() { // Initialize Bitmap final int width = 2; diff --git a/core/tests/coretests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java index ab41bd07ac6d..5cc915e45a6f 100644 --- a/core/tests/coretests/src/android/graphics/ColorStateListTest.java +++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java @@ -16,33 +16,41 @@ package android.graphics; +import static org.junit.Assert.assertEquals; + import android.content.res.ColorStateList; import android.content.res.Resources; -import android.test.AndroidTestCase; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.frameworks.coretests.R; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + /** - * Tests of {@link android.graphics.ColorStateList} + * Tests of {@link ColorStateList} */ -public class ColorStateListTest extends AndroidTestCase { +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ColorStateListTest { private Resources mResources; private int mFailureColor; - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); + @Before + public void setUp() throws Exception { + mResources = InstrumentationRegistry.getInstrumentation().getContext().getResources(); mFailureColor = mResources.getColor(R.color.failColor); } - @SmallTest + @Test public void testStateIsInList() throws Exception { ColorStateList colorStateList = mResources.getColorStateList(R.color.color1); int[] focusedState = {android.R.attr.state_focused}; @@ -50,7 +58,7 @@ public class ColorStateListTest extends AndroidTestCase { assertEquals(mResources.getColor(R.color.testcolor1), focusColor); } - @SmallTest + @Test public void testStateIsInList_proto() throws Exception { ColorStateList colorStateList = recreateFromProto( mResources.getColorStateList(R.color.color1)); @@ -59,7 +67,7 @@ public class ColorStateListTest extends AndroidTestCase { assertEquals(mResources.getColor(R.color.testcolor1), focusColor); } - @SmallTest + @Test public void testEmptyState() throws Exception { ColorStateList colorStateList = mResources.getColorStateList(R.color.color1); int[] emptyState = {}; @@ -67,7 +75,7 @@ public class ColorStateListTest extends AndroidTestCase { assertEquals(mResources.getColor(R.color.testcolor2), defaultColor); } - @SmallTest + @Test public void testEmptyState_proto() throws Exception { ColorStateList colorStateList = recreateFromProto( mResources.getColorStateList(R.color.color1)); @@ -76,22 +84,23 @@ public class ColorStateListTest extends AndroidTestCase { assertEquals(mResources.getColor(R.color.testcolor2), defaultColor); } - @SmallTest + @Test public void testGetColor() throws Exception { int defaultColor = mResources.getColor(R.color.color1); assertEquals(mResources.getColor(R.color.testcolor2), defaultColor); } - @SmallTest + @Test public void testGetColorWhenListHasNoDefault() throws Exception { int defaultColor = mResources.getColor(R.color.color_no_default); assertEquals(mResources.getColor(R.color.testcolor1), defaultColor); } - @SmallTest + @Test public void testLstar() throws Exception { + var cl = ColorStateList.valueOf(mResources.getColor(R.color.testcolor2)).withLStar(50.0f); int defaultColor = mResources.getColor(R.color.color_with_lstar); - assertEquals(mResources.getColor(R.color.testcolor3), defaultColor); + assertEquals(cl.getDefaultColor(), defaultColor); } private ColorStateList recreateFromProto(ColorStateList colorStateList) throws Exception { diff --git a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java index 52cc4cac4816..063bdf52fbd2 100644 --- a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java +++ b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java @@ -30,9 +30,11 @@ import android.util.Log; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.io.FileInputStream; @@ -43,6 +45,7 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @SmallTest +@RunWith(AndroidJUnit4.class) public class FontFileUtilTest { private static final String TAG = "FontFileUtilTest"; private static final String CACHE_FILE_PREFIX = ".font"; diff --git a/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java b/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java index 8a54e5b998e7..816bde603d36 100644 --- a/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java +++ b/core/tests/coretests/src/android/graphics/PaintFontVariationTest.java @@ -21,10 +21,9 @@ import static com.google.common.truth.Truth.assertThat; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; -import android.test.InstrumentationTestCase; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.text.flags.Flags; @@ -37,7 +36,7 @@ import org.junit.runner.RunWith; */ @SmallTest @RunWith(AndroidJUnit4.class) -public class PaintFontVariationTest extends InstrumentationTestCase { +public class PaintFontVariationTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java index 878ba703c8fe..56760d77e28b 100644 --- a/core/tests/coretests/src/android/graphics/PaintTest.java +++ b/core/tests/coretests/src/android/graphics/PaintTest.java @@ -18,19 +18,26 @@ package android.graphics; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; -import android.test.InstrumentationTestCase; import android.text.TextUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.text.flags.Flags; import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Arrays; import java.util.HashSet; @@ -38,13 +45,14 @@ import java.util.HashSet; /** * PaintTest tests {@link Paint}. */ -public class PaintTest extends InstrumentationTestCase { +@RunWith(AndroidJUnit4.class) +public class PaintTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private static final String FONT_PATH = "fonts/HintedAdvanceWidthTest-Regular.ttf"; - static void assertEquals(String message, float[] expected, float[] actual) { + static void assertFloatArrayEquals(String message, float[] expected, float[] actual) { if (expected.length != actual.length) { fail(message + " expected array length:<" + expected.length + "> but was:<" + actual.length + ">"); @@ -88,9 +96,10 @@ public class PaintTest extends InstrumentationTestCase { }; @SmallTest + @Test public void testHintingWidth() { final Typeface fontTypeface = Typeface.createFromAsset( - getInstrumentation().getContext().getAssets(), FONT_PATH); + InstrumentationRegistry.getInstrumentation().getContext().getAssets(), FONT_PATH); Paint paint = new Paint(); paint.setTypeface(fontTypeface); @@ -103,12 +112,14 @@ public class PaintTest extends InstrumentationTestCase { paint.setHinting(Paint.HINTING_OFF); paint.getTextWidths(String.valueOf(testCase.mText), widths); - assertEquals("Text width of '" + testCase.mText + "' without hinting is not expected.", + assertFloatArrayEquals( + "Text width of '" + testCase.mText + "' without hinting is not expected.", testCase.mWidthWithoutHinting, widths); paint.setHinting(Paint.HINTING_ON); paint.getTextWidths(String.valueOf(testCase.mText), widths); - assertEquals("Text width of '" + testCase.mText + "' with hinting is not expected.", + assertFloatArrayEquals( + "Text width of '" + testCase.mText + "' with hinting is not expected.", testCase.mWidthWithHinting, widths); } } @@ -131,9 +142,11 @@ public class PaintTest extends InstrumentationTestCase { return sb.toString(); } + @Test public void testHasGlyph_variationSelectors() { final Typeface fontTypeface = Typeface.createFromAsset( - getInstrumentation().getContext().getAssets(), "fonts/hasGlyphTestFont.ttf"); + InstrumentationRegistry.getInstrumentation().getContext().getAssets(), + "fonts/hasGlyphTestFont.ttf"); Paint p = new Paint(); p.setTypeface(fontTypeface); @@ -175,6 +188,7 @@ public class PaintTest extends InstrumentationTestCase { } } + @Test public void testGetTextRunAdvances() { { // LTR @@ -231,6 +245,7 @@ public class PaintTest extends InstrumentationTestCase { } } + @Test public void testGetTextRunAdvances_invalid() { Paint p = new Paint(); char[] text = "test".toCharArray(); @@ -284,6 +299,7 @@ public class PaintTest extends InstrumentationTestCase { } } + @Test public void testMeasureTextBidi() { Paint p = new Paint(); { @@ -340,18 +356,21 @@ public class PaintTest extends InstrumentationTestCase { } } + @Test public void testSetGetWordSpacing() { Paint p = new Paint(); - assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0. + assertEquals(0.0f, p.getWordSpacing(), 0.0f); // The default value should be 0. p.setWordSpacing(1.0f); - assertEquals(1.0f, p.getWordSpacing()); + assertEquals(1.0f, p.getWordSpacing(), 0.0f); p.setWordSpacing(-2.0f); - assertEquals(-2.0f, p.getWordSpacing()); + assertEquals(-2.0f, p.getWordSpacing(), 0.0f); } + @Test public void testGetUnderlinePositionAndThickness() { final Typeface fontTypeface = Typeface.createFromAsset( - getInstrumentation().getContext().getAssets(), "fonts/underlineTestFont.ttf"); + InstrumentationRegistry.getInstrumentation().getContext().getAssets(), + "fonts/underlineTestFont.ttf"); final Paint p = new Paint(); final int textSize = 100; p.setTextSize(textSize); @@ -391,6 +410,7 @@ public class PaintTest extends InstrumentationTestCase { return ccByChars; } + @Test public void testCluster() { final Paint p = new Paint(); p.setTextSize(100); @@ -417,6 +437,7 @@ public class PaintTest extends InstrumentationTestCase { } @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS) + @Test public void testDerivedFromSameTypeface() { final Paint p = new Paint(); @@ -432,6 +453,7 @@ public class PaintTest extends InstrumentationTestCase { } @RequiresFlagsEnabled(Flags.FLAG_TYPEFACE_CACHE_FOR_VAR_SETTINGS) + @Test public void testDerivedFromChained() { final Paint p = new Paint(); diff --git a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java index e1ca7dfb7cc2..fbaf502596f7 100644 --- a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java +++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java @@ -16,17 +16,17 @@ package android.graphics; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; -public class ThreadBitmapTest extends TestCase { - - @Override - protected void setUp() throws Exception { - } +@RunWith(AndroidJUnit4.class) +public class ThreadBitmapTest { @LargeTest + @Test public void testCreation() { for (int i = 0; i < 200; i++) { @@ -44,4 +44,3 @@ public class ThreadBitmapTest extends TestCase { public void run() {} } } - diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java index 14292725506e..2b6eda8f0988 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java @@ -39,6 +39,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.text.flags.Flags; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -514,9 +516,14 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + if (Flags.deprecateElegantTextHeightApi()) { + // Calling setElegantTextHeight is no-op. + assertTrue(paint.isElegantTextHeight()); + } else { + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); + assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); + } } @Test @@ -553,9 +560,14 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); + if (Flags.deprecateElegantTextHeightApi()) { + // Calling setElegantTextHeight is no-op. + assertTrue(paint.isElegantTextHeight()); + } else { + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); + assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); + } testTypeface = fontMap.get("sans-serif"); assertNotNull(testTypeface); @@ -566,9 +578,14 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); + if (Flags.deprecateElegantTextHeightApi()) { + // Calling setElegantTextHeight is no-op. + assertTrue(paint.isElegantTextHeight()); + } else { + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); + assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); + assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); + } } @Test diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index 7a5b3064b3a3..a270848b98a3 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -73,9 +73,13 @@ public class DisplayManagerGlobalTest { public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final long DISPLAY_CHANGE_EVENTS = + DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; + private static final long ALL_DISPLAY_EVENTS = DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DISPLAY_CHANGE_EVENTS | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; @Mock @@ -127,7 +131,7 @@ public class DisplayManagerGlobalTest { final DisplayInfo newDisplayInfo = new DisplayInfo(); newDisplayInfo.rotation++; doReturn(newDisplayInfo).when(mDisplayManager).getDisplayInfo(displayId); - callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); waitForHandler(); Mockito.verify(mDisplayListener).onDisplayChanged(eq(displayId)); Mockito.verifyNoMoreInteractions(mDisplayListener); @@ -186,8 +190,8 @@ public class DisplayManagerGlobalTest { mDisplayManagerGlobal.registerDisplayListener(mDisplayListener, mHandler, ALL_DISPLAY_EVENTS - & ~DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, null); - callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + & ~DISPLAY_CHANGE_EVENTS, null); + callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); waitForHandler(); Mockito.verifyZeroInteractions(mDisplayListener); @@ -257,8 +261,7 @@ public class DisplayManagerGlobalTest { | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, null /* packageName */); mDisplayManagerGlobal.registerDisplayListener(mDisplayListener2, mHandler, - DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, - null /* packageName */); + DISPLAY_CHANGE_EVENTS, null /* packageName */); mDisplayManagerGlobal.handleDisplayChangeFromWindowManager(321); waitForHandler(); @@ -304,8 +307,7 @@ public class DisplayManagerGlobalTest { assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED, mDisplayManagerGlobal .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_ADDED, 0)); - assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED, - mDisplayManagerGlobal + assertEquals(DISPLAY_CHANGE_EVENTS, mDisplayManagerGlobal .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, 0)); assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, mDisplayManagerGlobal diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt index 4a227d8ff1ef..255d09b854bd 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -86,7 +86,7 @@ class DisplayTopologyTest { verifyDisplay(display1, displayId1, width1, height1, noOfChildren = 1) val display2 = display1.children[0] - verifyDisplay(display1.children[0], displayId2, width2, height2, POSITION_TOP, + verifyDisplay(display2, displayId2, width2, height2, POSITION_TOP, offset = width1 / 2 - width2 / 2, noOfChildren = 1) var display = display2 @@ -99,6 +99,76 @@ class DisplayTopologyTest { } @Test + fun updateDisplay() { + val displayId = 1 + val width = 800f + val height = 600f + + val newWidth = 1000f + val newHeight = 500f + topology.addDisplay(displayId, width, height) + assertThat(topology.updateDisplay(displayId, newWidth, newHeight)).isTrue() + + assertThat(topology.primaryDisplayId).isEqualTo(displayId) + verifyDisplay(topology.root!!, displayId, newWidth, newHeight, noOfChildren = 0) + } + + @Test + fun updateDisplay_notUpdated() { + val displayId = 1 + val width = 800f + val height = 600f + topology.addDisplay(displayId, width, height) + + // Same size + assertThat(topology.updateDisplay(displayId, width, height)).isFalse() + + // Display doesn't exist + assertThat(topology.updateDisplay(/* displayId= */ 100, width, height)).isFalse() + + assertThat(topology.primaryDisplayId).isEqualTo(displayId) + verifyDisplay(topology.root!!, displayId, width, height, noOfChildren = 0) + } + + @Test + fun updateDisplayDoesNotAffectDefaultTopology() { + val width1 = 700f + val height = 600f + topology.addDisplay(/* displayId= */ 1, width1, height) + + val width2 = 800f + val noOfDisplays = 30 + for (i in 2..noOfDisplays) { + topology.addDisplay(/* displayId= */ i, width2, height) + } + + val displaysToUpdate = arrayOf(3, 7, 18) + val newWidth = 1000f + val newHeight = 1500f + for (i in displaysToUpdate) { + assertThat(topology.updateDisplay(/* displayId= */ i, newWidth, newHeight)).isTrue() + } + + assertThat(topology.primaryDisplayId).isEqualTo(1) + + val display1 = topology.root!! + verifyDisplay(display1, id = 1, width1, height, noOfChildren = 1) + + val display2 = display1.children[0] + verifyDisplay(display2, id = 2, width2, height, POSITION_TOP, + offset = width1 / 2 - width2 / 2, noOfChildren = 1) + + var display = display2 + for (i in 3..noOfDisplays) { + display = display.children[0] + // The last display should have no children + verifyDisplay(display, id = i, if (i in displaysToUpdate) newWidth else width2, + if (i in displaysToUpdate) newHeight else height, POSITION_RIGHT, offset = 0f, + noOfChildren = if (i < noOfDisplays) 1 else 0) + } + } + + @Test fun removeDisplays() { val displayId1 = 1 val width1 = 800f @@ -117,7 +187,7 @@ class DisplayTopologyTest { } var removedDisplays = arrayOf(20) - topology.removeDisplay(20) + assertThat(topology.removeDisplay(20)).isTrue() assertThat(topology.primaryDisplayId).isEqualTo(displayId1) @@ -139,11 +209,11 @@ class DisplayTopologyTest { noOfChildren = if (i < noOfDisplays) 1 else 0) } - topology.removeDisplay(22) + assertThat(topology.removeDisplay(22)).isTrue() removedDisplays += 22 - topology.removeDisplay(23) + assertThat(topology.removeDisplay(23)).isTrue() removedDisplays += 23 - topology.removeDisplay(25) + assertThat(topology.removeDisplay(25)).isTrue() removedDisplays += 25 assertThat(topology.primaryDisplayId).isEqualTo(displayId1) @@ -174,7 +244,7 @@ class DisplayTopologyTest { val height = 600f topology.addDisplay(displayId, width, height) - topology.removeDisplay(displayId) + assertThat(topology.removeDisplay(displayId)).isTrue() assertThat(topology.primaryDisplayId).isEqualTo(Display.INVALID_DISPLAY) assertThat(topology.root).isNull() @@ -187,7 +257,7 @@ class DisplayTopologyTest { val height = 600f topology.addDisplay(displayId, width, height) - topology.removeDisplay(3) + assertThat(topology.removeDisplay(3)).isFalse() assertThat(topology.primaryDisplayId).isEqualTo(displayId) verifyDisplay(topology.root!!, displayId, width, height, noOfChildren = 0) @@ -203,7 +273,7 @@ class DisplayTopologyTest { topology = DisplayTopology(/* root= */ null, displayId2) topology.addDisplay(displayId1, width, height) topology.addDisplay(displayId2, width, height) - topology.removeDisplay(displayId2) + assertThat(topology.removeDisplay(displayId2)).isTrue() assertThat(topology.primaryDisplayId).isEqualTo(displayId1) verifyDisplay(topology.root!!, displayId1, width, height, noOfChildren = 0) diff --git a/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java b/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java new file mode 100644 index 000000000000..45864b01c795 --- /dev/null +++ b/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.advancedprotection; + +import static android.security.advancedprotection.AdvancedProtectionManager.ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG; +import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_FEATURE; +import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_TYPE; +import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G; +import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION; +import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING; +import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import android.content.Intent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AdvancedProtectionManagerTest { + private static final int FEATURE_ID_INVALID = -1; + private static final int SUPPORT_DIALOG_TYPE_INVALID = -1; + + @Test + public void testCreateSupportIntent_validFeature_validTypeUnknown_createsIntent() { + Intent intent = AdvancedProtectionManager.createSupportIntent( + FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_UNKNOWN); + + assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction()); + assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra( + EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID)); + assertEquals(SUPPORT_DIALOG_TYPE_UNKNOWN, intent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, + SUPPORT_DIALOG_TYPE_INVALID)); + } + + @Test + public void testCreateSupportIntent_validFeature_validTypeBlockedInteraction_createsIntent() { + Intent intent = AdvancedProtectionManager.createSupportIntent( + FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION); + + assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction()); + assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra( + EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID)); + assertEquals(SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION, intent.getIntExtra( + EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_INVALID)); + } + + @Test + public void testCreateSupportIntent_validFeature_validTypeDisabledSetting_createsIntent() { + Intent intent = AdvancedProtectionManager.createSupportIntent( + FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_DISABLED_SETTING); + + assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction()); + assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra( + EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID)); + assertEquals(SUPPORT_DIALOG_TYPE_DISABLED_SETTING, intent.getIntExtra( + EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_INVALID)); + } + + @Test + public void testCreateSupportIntent_validFeature_invalidType_throwsIllegalArgument() { + assertThrows(IllegalArgumentException.class, () -> + AdvancedProtectionManager.createSupportIntent(FEATURE_ID_DISALLOW_CELLULAR_2G, + SUPPORT_DIALOG_TYPE_INVALID)); + } + + @Test + public void testCreateSupportIntent_invalidFeature_validType_throwsIllegalArgument() { + assertThrows(IllegalArgumentException.class, () -> + AdvancedProtectionManager.createSupportIntent(FEATURE_ID_INVALID, + SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION)); + } + + @Test + public void testCreateSupportIntent_invalidFeature_invalidType_throwsIllegalArgument() { + assertThrows(IllegalArgumentException.class, () -> + AdvancedProtectionManager.createSupportIntent(FEATURE_ID_INVALID, + SUPPORT_DIALOG_TYPE_INVALID)); + } +} diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index fb1efa86c236..8b4f714fbf65 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -1171,6 +1171,88 @@ public class ViewFrameRateTest { waitForAfterDraw(); } + @Test + public void ignoreHeuristicWhenFling() throws Throwable { + if (!ViewProperties.vrr_enabled().orElse(true)) { + return; + } + + waitForFrameRateCategoryToSettle(); + FrameLayout host = new FrameLayout(mActivity); + View childView = new View(mActivity); + float velocity = 1000; + + TranslateAnimation translateAnimation = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0f, // fromXDelta + Animation.RELATIVE_TO_PARENT, 0f, // toXDelta + Animation.RELATIVE_TO_PARENT, 1f, // fromYDelta (100%p) + Animation.RELATIVE_TO_PARENT, 0f // toYDelta + ); + translateAnimation.setDuration(100); + + mActivityRule.runOnUiThread(() -> { + ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mActivity.setContentView(host, fullSize); + host.setFrameContentVelocity(velocity); + ViewGroupOverlay overlay = host.getOverlay(); + overlay.add(childView); + assertEquals(velocity, host.getFrameContentVelocity()); + assertEquals(host.getFrameContentVelocity(), + ((View) childView.getParent()).getFrameContentVelocity()); + + mMovingView.startAnimation(translateAnimation); + + // The frame rate should be "Normal" during fling gestures, + // even if there's a moving View. + assertEquals(FRAME_RATE_CATEGORY_NORMAL, + mViewRoot.getLastPreferredFrameRateCategory()); + }); + waitForAfterDraw(); + } + + @Test + public void ignoreHeuristicWhenFlingMovementFirst() throws Throwable { + if (!ViewProperties.vrr_enabled().orElse(true)) { + return; + } + + waitForFrameRateCategoryToSettle(); + FrameLayout host = new FrameLayout(mActivity); + View childView = new View(mActivity); + float velocity = 1000; + + TranslateAnimation translateAnimation = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0f, // fromXDelta + Animation.RELATIVE_TO_PARENT, 0f, // toXDelta + Animation.RELATIVE_TO_PARENT, 1f, // fromYDelta (100%p) + Animation.RELATIVE_TO_PARENT, 0f // toYDelta + ); + translateAnimation.setDuration(100); + + mActivityRule.runOnUiThread(() -> { + mMovingView.startAnimation(translateAnimation); + + ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mActivity.setContentView(host, fullSize); + host.setFrameContentVelocity(velocity); + ViewGroupOverlay overlay = host.getOverlay(); + overlay.add(childView); + assertEquals(velocity, host.getFrameContentVelocity()); + assertEquals(host.getFrameContentVelocity(), + ((View) childView.getParent()).getFrameContentVelocity()); + + // The frame rate should be "Normal" during fling gestures, + // even if there's a moving View. + assertEquals(FRAME_RATE_CATEGORY_NORMAL, + mViewRoot.getLastPreferredFrameRateCategory()); + }); + waitForAfterDraw(); + } + private void runAfterDraw(@NonNull Runnable runnable) { Handler handler = new Handler(Looper.getMainLooper()); mAfterDrawLatch = new CountDownLatch(1); diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index ed9fc1c9e547..18ab52dba8f3 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -25,7 +25,7 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT; import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; -import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; +import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; @@ -861,10 +861,10 @@ public class ViewRootImplTest { assertEquals(mViewRootImpl.getFrameRateCompatibility(), FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); assertFalse(mViewRootImpl.isFrameRateConflicted()); - mViewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_GTE); + mViewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_AT_LEAST); if (toolkitFrameRateVelocityMappingReadOnly()) { assertEquals(24, mViewRootImpl.getPreferredFrameRate(), 0.1); - assertEquals(FRAME_RATE_COMPATIBILITY_GTE, + assertEquals(FRAME_RATE_COMPATIBILITY_AT_LEAST, mViewRootImpl.getFrameRateCompatibility()); assertFalse(mViewRootImpl.isFrameRateConflicted()); } else { @@ -888,10 +888,10 @@ public class ViewRootImplTest { sInstrumentation.runOnMainSync(() -> { assertFalse(mViewRootImpl.isFrameRateConflicted()); - mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); + mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_AT_LEAST); if (toolkitFrameRateVelocityMappingReadOnly()) { assertEquals(60, mViewRootImpl.getPreferredFrameRate(), 0.1); - assertEquals(FRAME_RATE_COMPATIBILITY_GTE, + assertEquals(FRAME_RATE_COMPATIBILITY_AT_LEAST, mViewRootImpl.getFrameRateCompatibility()); } else { assertEquals(FRAME_RATE_CATEGORY_HIGH, @@ -904,7 +904,7 @@ public class ViewRootImplTest { mViewRootImpl.getFrameRateCompatibility()); // Should be false since 60 is a divisor of 120. assertFalse(mViewRootImpl.isFrameRateConflicted()); - mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); + mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_AT_LEAST); assertEquals(120, mViewRootImpl.getPreferredFrameRate(), 0.1); // compatibility should be remained the same (FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) // since the frame rate 60 is smaller than 120. diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index 5a4561d7c6ea..f87b6994900f 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -266,6 +266,11 @@ public class ContentCaptureSessionTest { } @Override + void internalNotifySessionFlushEvent(int sessionId) { + throw new UnsupportedOperationException("should not have been called"); + } + + @Override void internalNotifyChildSessionStarted(int parentSessionId, int childSessionId, @NonNull ContentCaptureContext clientContext) { throw new UnsupportedOperationException("should not have been called"); diff --git a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java index fdc00ba65255..610758d378de 100644 --- a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java +++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java @@ -16,8 +16,6 @@ package android.window; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static org.junit.Assert.assertEquals; @@ -30,15 +28,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager.TaskDescription; -import android.content.ComponentName; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorSpace; -import android.graphics.Point; import android.graphics.Rect; -import android.hardware.HardwareBuffer; -import android.view.Surface; -import android.view.SurfaceControl; import android.view.WindowInsets; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -54,7 +46,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class SnapshotDrawerUtilsTest { - private SnapshotDrawerUtils.SnapshotSurface mSnapshotSurface; + private SnapshotDrawerUtils.SystemBarBackgroundPainter mSystemBarBackgroundPainter; private void setupSurface(int width, int height) { setupSurface(width, height, new Rect(), FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, @@ -70,31 +62,14 @@ public class SnapshotDrawerUtilsTest { // taskBounds assertEquals(width, taskBounds.width()); assertEquals(height, taskBounds.height()); - Point taskSize = new Point(taskBounds.width(), taskBounds.height()); - final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets); TaskDescription taskDescription = createTaskDescription(Color.WHITE, Color.RED, Color.BLUE); - mSnapshotSurface = new SnapshotDrawerUtils.SnapshotSurface( - new SurfaceControl(), snapshot, "Test"); - mSnapshotSurface.initiateSystemBarPainter(windowFlags, 0, 0, - taskDescription, WindowInsets.Type.defaultVisible()); - } - - private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize, - Rect contentInsets) { - final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, - 1, HardwareBuffer.USAGE_CPU_READ_RARELY); - return new TaskSnapshot( - System.currentTimeMillis(), - 0 /* captureTime */, - new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, - Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */, - false, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, - 0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */, - 0 /* uiMode */); + mSystemBarBackgroundPainter = new SnapshotDrawerUtils.SystemBarBackgroundPainter( + windowFlags, 0 /* windowPrivateFlags */, 0 /* appearance */, + taskDescription, 1f /* scale */, WindowInsets.Type.defaultVisible()); + mSystemBarBackgroundPainter.setInsets(contentInsets); } private static TaskDescription createTaskDescription(int background, @@ -107,134 +82,14 @@ public class SnapshotDrawerUtilsTest { } @Test - public void fillEmptyBackground_fillHorizontally() { - setupSurface(200, 100); - final Canvas mockCanvas = mock(Canvas.class); - when(mockCanvas.getWidth()).thenReturn(200); - when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200)); - verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any()); - } - - @Test - public void fillEmptyBackground_fillVertically() { - setupSurface(100, 200); - final Canvas mockCanvas = mock(Canvas.class); - when(mockCanvas.getWidth()).thenReturn(100); - when(mockCanvas.getHeight()).thenReturn(200); - mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100)); - verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any()); - } - - @Test - public void fillEmptyBackground_fillBoth() { - setupSurface(200, 200); - final Canvas mockCanvas = mock(Canvas.class); - when(mockCanvas.getWidth()).thenReturn(200); - when(mockCanvas.getHeight()).thenReturn(200); - mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100)); - verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any()); - verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any()); - } - - @Test - public void fillEmptyBackground_dontFill_sameSize() { - setupSurface(100, 100); - final Canvas mockCanvas = mock(Canvas.class); - when(mockCanvas.getWidth()).thenReturn(100); - when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100)); - verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); - } - - @Test - public void fillEmptyBackground_dontFill_bitmapLarger() { - setupSurface(100, 100); - final Canvas mockCanvas = mock(Canvas.class); - when(mockCanvas.getWidth()).thenReturn(100); - when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200)); - verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); - } - - @Test - public void testCalculateSnapshotCrop() { - final Rect contentInsets = new Rect(0, 10, 0, 10); - setupSurface(100, 100, contentInsets, 0, new Rect(0, 0, 100, 100)); - assertEquals(new Rect(0, 0, 100, 90), - mSnapshotSurface.calculateSnapshotCrop(contentInsets)); - } - - @Test - public void testCalculateSnapshotCrop_taskNotOnTop() { - final Rect contentInsets = new Rect(0, 10, 0, 10); - final Rect bounds = new Rect(0, 50, 100, 150); - setupSurface(100, 100, contentInsets, 0, bounds); - mSnapshotSurface.setFrames(bounds, contentInsets); - assertEquals(new Rect(0, 10, 100, 90), - mSnapshotSurface.calculateSnapshotCrop(contentInsets)); - } - - @Test - public void testCalculateSnapshotCrop_navBarLeft() { - final Rect contentInsets = new Rect(10, 0, 0, 0); - setupSurface(100, 100, contentInsets, 0, new Rect(0, 0, 100, 100)); - assertEquals(new Rect(10, 0, 100, 100), - mSnapshotSurface.calculateSnapshotCrop(contentInsets)); - } - - @Test - public void testCalculateSnapshotCrop_navBarRight() { - final Rect contentInsets = new Rect(0, 10, 10, 0); - setupSurface(100, 100, contentInsets, 0, new Rect(0, 0, 100, 100)); - assertEquals(new Rect(0, 0, 90, 100), - mSnapshotSurface.calculateSnapshotCrop(contentInsets)); - } - - @Test - public void testCalculateSnapshotCrop_waterfall() { - final Rect contentInsets = new Rect(5, 10, 5, 10); - setupSurface(100, 100, contentInsets, 0, new Rect(0, 0, 100, 100)); - assertEquals(new Rect(5, 0, 95, 90), - mSnapshotSurface.calculateSnapshotCrop(contentInsets)); - } - - @Test - public void testCalculateSnapshotFrame() { - setupSurface(100, 100); - final Rect insets = new Rect(0, 10, 0, 10); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); - assertEquals(new Rect(0, 0, 100, 80), - mSnapshotSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90))); - } - - @Test - public void testCalculateSnapshotFrame_navBarLeft() { - setupSurface(100, 100); - final Rect insets = new Rect(10, 10, 0, 0); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); - assertEquals(new Rect(10, 0, 100, 90), - mSnapshotSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100))); - } - - @Test - public void testCalculateSnapshotFrame_waterfall() { - setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, new Rect(0, 0, 100, 100)); - final Rect insets = new Rect(0, 10, 0, 10); - mSnapshotSurface.setFrames(new Rect(5, 0, 95, 100), insets); - assertEquals(new Rect(0, 0, 90, 90), - mSnapshotSurface.calculateSnapshotFrame(new Rect(5, 0, 95, 90))); - } - - @Test public void testDrawStatusBarBackground() { setupSurface(100, 100); final Rect insets = new Rect(0, 10, 10, 0); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100)); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, new Rect(0, 0, 50, 100)); verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any()); } @@ -242,11 +97,11 @@ public class SnapshotDrawerUtilsTest { public void testDrawStatusBarBackground_nullFrame() { setupSurface(100, 100); final Rect insets = new Rect(0, 10, 10, 0); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawStatusBarBackground(mockCanvas, null); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, null /* alreadyDrawnFrame */); verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any()); } @@ -254,11 +109,11 @@ public class SnapshotDrawerUtilsTest { public void testDrawStatusBarBackground_nope() { setupSurface(100, 100); final Rect insets = new Rect(0, 10, 10, 0); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100)); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, new Rect(0, 0, 100, 100)); verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any()); } @@ -267,11 +122,11 @@ public class SnapshotDrawerUtilsTest { final Rect insets = new Rect(0, 10, 0, 10); setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, new Rect(0, 0, 100, 100)); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawNavigationBarBackground(mockCanvas); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, null /* alreadyDrawnFrame */); verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any()); } @@ -280,11 +135,11 @@ public class SnapshotDrawerUtilsTest { final Rect insets = new Rect(10, 10, 0, 0); setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, new Rect(0, 0, 100, 100)); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawNavigationBarBackground(mockCanvas); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, null /* alreadyDrawnFrame */); verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any()); } @@ -293,11 +148,11 @@ public class SnapshotDrawerUtilsTest { final Rect insets = new Rect(0, 10, 10, 0); setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, new Rect(0, 0, 100, 100)); - mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets); + mSystemBarBackgroundPainter.setInsets(insets); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); when(mockCanvas.getHeight()).thenReturn(100); - mSnapshotSurface.drawNavigationBarBackground(mockCanvas); + mSystemBarBackgroundPainter.drawDecors(mockCanvas, null /* alreadyDrawnFrame */); verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any()); } } diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java index bb2fe1bcfc64..84ff40f0dcf0 100644 --- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java +++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java @@ -33,11 +33,15 @@ import android.app.ActivityThread; import android.content.res.Configuration; import android.os.IBinder; import android.os.RemoteException; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.view.IWindowManager; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -58,6 +62,9 @@ public class WindowTokenClientControllerTest { @Rule public final MockitoRule mockito = MockitoJUnit.rule(); + @Rule + public SetFlagsRule setFlagsRule = new SetFlagsRule(); + @Mock private IWindowManager mWindowManagerService; @Mock @@ -161,6 +168,7 @@ public class WindowTokenClientControllerTest { verify(mWindowManagerService).detachWindowContext(mWindowTokenClient); } + @EnableFlags(Flags.FLAG_TRACK_SYSTEM_UI_CONTEXT_BEFORE_WMS) @Test public void testAttachToDisplayContent_keepTrackWithoutWMS() { // WMS is not initialized diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java index 00b4f464de50..d1fbc77cbd46 100644 --- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doNothing; @@ -44,20 +45,27 @@ import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.UserInfo; +import android.hardware.input.IInputManager; +import android.hardware.input.InputManagerGlobal; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.ravenwood.RavenwoodRule; import android.provider.Settings; import android.test.mock.MockContentResolver; +import android.view.InputDevice; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.internal.widget.flags.Flags; import com.google.android.collect.Lists; @@ -76,6 +84,8 @@ import java.util.concurrent.CompletableFuture; public class LockPatternUtilsTest { @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private ILockSettings mLockSettings; private static final int USER_ID = 1; @@ -395,4 +405,156 @@ public class LockPatternUtilsTest { } }; } + + private InputManagerGlobal.TestSession configureExternalHardwareTest(InputDevice[] devices) + throws RemoteException { + final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()); + final ILockSettings ils = mock(ILockSettings.class); + when(ils.getBoolean(anyString(), anyBoolean(), anyInt())).thenThrow(RemoteException.class); + mLockPatternUtils = new LockPatternUtils(context, ils); + + IInputManager inputManagerMock = mock(IInputManager.class); + + int[] deviceIds = new int[devices.length]; + + for (int i = 0; i < devices.length; i++) { + when(inputManagerMock.getInputDevice(i)).thenReturn(devices[i]); + } + + when(inputManagerMock.getInputDeviceIds()).thenReturn(deviceIds); + InputManagerGlobal.TestSession session = + InputManagerGlobal.createTestSession(inputManagerMock); + + return session; + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_noDevicesAttached() throws RemoteException { + InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]); + assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_noEnabledDeviceAttached() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder.setEnabled(false); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_withoutHwKeyboard() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder.setEnabled(true).setSources(InputDevice.SOURCE_TOUCHSCREEN); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_withoutFullHwKeyboard() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_KEYBOARD) + .setKeyboardType(InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_withHwKeyboardOldDefault() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_KEYBOARD) + .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isPinEnhancedPrivacyEnabled_withHwKeyboard() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_KEYBOARD) + .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertTrue(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isVisiblePatternEnabled_noDevices() throws RemoteException { + InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]); + assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isVisiblePatternEnabled_noEnabledDevices() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder.setEnabled(false); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isVisiblePatternEnabled_noPointingDevices() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_TOUCHSCREEN); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID)); + session.close(); + } + + @Test + @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isVisiblePatternEnabled_externalPointingDevice() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_CLASS_POINTER); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertFalse(mLockPatternUtils.isVisiblePatternEnabled(USER_ID)); + session.close(); + } + + @Test + @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT) + public void isVisiblePatternEnabled_externalPointingDeviceOldDefault() throws RemoteException { + InputDevice.Builder builder = new InputDevice.Builder(); + builder + .setEnabled(true) + .setSources(InputDevice.SOURCE_CLASS_POINTER); + InputManagerGlobal.TestSession session = + configureExternalHardwareTest(new InputDevice[]{builder.build()}); + assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID)); + session.close(); + } } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2398e7134b34..f136e065a405 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -125,6 +125,7 @@ applications that come with the platform <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/> <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"/> + <permission name="android.permission.RESOLVE_COMPONENT_FOR_UID"/> </privapp-permissions> <privapp-permissions package="com.android.phone"> @@ -609,6 +610,8 @@ applications that come with the platform <permission name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" /> <!-- Permission required for CTS test - KeyguardLockedStateApiTest --> <permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" /> + <!-- Permission required for CTS test - CtsContentProviderMultiUserTest --> + <permission name="android.permission.RESOLVE_COMPONENT_FOR_UID"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 5f1fb4b44613..500548500927 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -171,3 +171,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "task_view_repository" + namespace: "multitasking" + description: "Factor task-view state tracking out of taskviewtransitions" + bug: "384976265" +} diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp index 41d1b5c15369..eecf199a3ec2 100644 --- a/libs/WindowManager/Shell/multivalentTests/Android.bp +++ b/libs/WindowManager/Shell/multivalentTests/Android.bp @@ -55,6 +55,7 @@ android_robolectric_test { "truth", "flag-junit-base", "flag-junit", + "testables", ], auto_gen_config: true, } @@ -77,6 +78,7 @@ android_test { "truth", "platform-test-annotations", "platform-test-rules", + "testables", ], libs: [ "android.test.base.stubs.system", diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt index 0d8f80935f5a..3e01256fd67c 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt @@ -16,6 +16,8 @@ package com.android.wm.shell.bubbles.bar +import android.animation.AnimatorTestRule +import android.app.ActivityManager import android.content.Context import android.graphics.Insets import android.graphics.Rect @@ -23,7 +25,6 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.widget.FrameLayout -import androidx.core.animation.AnimatorTestRule import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -36,27 +37,34 @@ import com.android.wm.shell.bubbles.BubbleExpandedViewManager import com.android.wm.shell.bubbles.BubbleLogger import com.android.wm.shell.bubbles.BubbleOverflow import com.android.wm.shell.bubbles.BubblePositioner +import com.android.wm.shell.bubbles.BubbleTaskView import com.android.wm.shell.bubbles.DeviceConfig import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager import com.android.wm.shell.bubbles.FakeBubbleFactory -import com.android.wm.shell.bubbles.FakeBubbleTaskViewFactory +import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import org.junit.After import org.junit.Before -import org.junit.ClassRule +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever /** Tests for [BubbleBarAnimationHelper] */ @SmallTest @RunWith(AndroidJUnit4::class) class BubbleBarAnimationHelperTest { - companion object { - @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule() + @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this) + companion object { const val SCREEN_WIDTH = 2000 const val SCREEN_HEIGHT = 1000 } @@ -148,6 +156,26 @@ class BubbleBarAnimationHelperTest { } @Test + fun animateSwitch_bubbleToBubble_updateTaskBounds() { + val fromBubble = createBubble("from").initialize(container) + val toBubbleTaskController = mock<TaskViewTaskController>() + val toBubble = createBubble("to", toBubbleTaskController).initialize(container) + + getInstrumentation().runOnMainSync { + animationHelper.animateSwitch(fromBubble, toBubble) {} + // Start the animation, but don't finish + animatorTestRule.advanceTimeBy(100) + } + getInstrumentation().waitForIdleSync() + // Clear invocations to ensure that bounds update happens after animation ends + clearInvocations(toBubbleTaskController) + getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) } + getInstrumentation().waitForIdleSync() + + verify(toBubbleTaskController).setWindowBounds(any()) + } + + @Test fun animateSwitch_bubbleToOverflow_oldHiddenNewShown() { val fromBubble = createBubble(key = "from").initialize(container) val overflow = createOverflow().initialize(container) @@ -193,13 +221,43 @@ class BubbleBarAnimationHelperTest { assertThat(toBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse() } - private fun createBubble(key: String): Bubble { + @Test + fun animateToRestPosition_updateTaskBounds() { + val taskController = mock<TaskViewTaskController>() + val bubble = createBubble("key", taskController).initialize(container) + + getInstrumentation().runOnMainSync { + animationHelper.animateExpansion(bubble) {} + animatorTestRule.advanceTimeBy(1000) + } + getInstrumentation().waitForIdleSync() + getInstrumentation().runOnMainSync { + animationHelper.animateToRestPosition() + animatorTestRule.advanceTimeBy(100) + } + // Clear invocations to ensure that bounds update happens after animation ends + clearInvocations(taskController) + getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) } + getInstrumentation().waitForIdleSync() + + verify(taskController).setWindowBounds(any()) + } + + private fun createBubble( + key: String, + taskViewTaskController: TaskViewTaskController = mock<TaskViewTaskController>(), + ): Bubble { + val taskView = TaskView(context, taskViewTaskController) + val taskInfo = mock<ActivityManager.RunningTaskInfo>() + whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo) + val bubbleTaskView = BubbleTaskView(taskView, mainExecutor) + val bubbleBarExpandedView = FakeBubbleFactory.createExpandedView( context, bubblePositioner, expandedViewManager, - FakeBubbleTaskViewFactory(context, mainExecutor).create(), + bubbleTaskView, mainExecutor, bgExecutor, bubbleLogger, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java index 3e8a9b64dac6..3188e5b9c6d2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java @@ -463,6 +463,7 @@ public class BubbleBarAnimationHelper { super.onAnimationEnd(animation); bbev.resetPivot(); bbev.setDragging(false); + updateExpandedView(bbev); } }); startNewAnimator(animatorSet); 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 c74bf53268f9..9ebb7f5aa270 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 @@ -643,7 +643,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged t.setPosition(animatingLeash, x, endY); t.setAlpha(animatingLeash, 1.f); } - dispatchEndPositioning(mDisplayId, mCancelled, t); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + dispatchEndPositioning(mDisplayId, mCancelled, t); + } if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) { ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_ANIMATION_RUNNING); @@ -659,6 +661,14 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged ImeTracker.forLogging().onCancelled(mStatsToken, ImeTracker.PHASE_WM_ANIMATION_RUNNING); } + if (android.view.inputmethod.Flags.refactorInsetsController()) { + // In split screen, we also set {@link + // WindowContainer#mExcludeInsetsTypes} but this should only happen after + // the IME client visibility was set. Otherwise the insets will we + // dispatched too early, and we get a flicker. Thus, only dispatching it + // after reporting that the IME is hidden to system server. + dispatchEndPositioning(mDisplayId, mCancelled, t); + } if (DEBUG_IME_VISIBILITY) { EventLog.writeEvent(IMF_IME_REMOTE_ANIM_END, mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE, 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 21c44c9b92ee..4bcec702281d 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 @@ -571,9 +571,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // For flexible split, expand app offscreen as well if (mDividerSnapAlgorithm.areOffscreenRatiosSupported()) { if (position <= mDividerSnapAlgorithm.getMiddleTarget().position) { - bounds1.top = bounds1.bottom - bounds2.width(); + bounds1.top = bounds1.bottom - bounds2.height(); } else { - bounds2.bottom = bounds2.top + bounds1.width(); + bounds2.bottom = bounds2.top + bounds1.height(); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java index b141bebbe8b1..1cc58c870540 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java @@ -32,6 +32,7 @@ import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.window.flags.Flags; import com.android.wm.shell.R; /** @@ -172,6 +173,9 @@ public class UserAspectRatioSettingsLayout extends LinearLayout { @Override public void onAnimationEnd(Animator animation) { view.setVisibility(View.GONE); + if (Flags.releaseUserAspectRatioWm()) { + mWindowManager.release(); + } } }); fadeOut.start(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt index ff6fb59d6494..ceef69969d9a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt @@ -541,6 +541,9 @@ class DesktopModeEventLogger { TASK_FINISHED(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED), SCREEN_OFF(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF), TASK_MINIMIZED(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_MINIMIZED), + TASK_MOVED_TO_BACK( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_MOVED_TO_BACK + ), } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt index dfa2d9b6bb63..ccfbbeef89c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt @@ -38,6 +38,7 @@ import androidx.core.util.putAll import com.android.internal.protolog.ProtoLog import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON @@ -236,6 +237,7 @@ class DesktopModeLoggerTransitionObserver( ) { // Sessions is finishing, log task updates followed by an exit event identifyAndLogTaskUpdates( + transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, ) @@ -252,12 +254,14 @@ class DesktopModeLoggerTransitionObserver( desktopModeEventLogger.logSessionEnter(getEnterReason(transitionInfo)) identifyAndLogTaskUpdates( + transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, ) } else if (isSessionActive) { // Session is neither starting, nor finishing, log task updates if there are any identifyAndLogTaskUpdates( + transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, ) @@ -270,6 +274,7 @@ class DesktopModeLoggerTransitionObserver( /** Compare the old and new state of taskInfos and identify and log the changes */ private fun identifyAndLogTaskUpdates( + transitionInfo: TransitionInfo, preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, ) { @@ -304,9 +309,19 @@ class DesktopModeLoggerTransitionObserver( // find old tasks that were removed preTransitionVisibleFreeformTasks.forEach { taskId, taskInfo -> if (!postTransitionVisibleFreeformTasks.containsKey(taskId)) { - desktopModeEventLogger.logTaskRemoved( - buildTaskUpdateForTask(taskInfo, postTransitionVisibleFreeformTasks.size()) - ) + val minimizeReason = + if (transitionInfo.type == Transitions.TRANSIT_MINIMIZE) { + MinimizeReason.MINIMIZE_BUTTON + } else { + null + } + val taskUpdate = + buildTaskUpdateForTask( + taskInfo, + postTransitionVisibleFreeformTasks.size(), + minimizeReason, + ) + desktopModeEventLogger.logTaskRemoved(taskUpdate) Trace.setCounter( Trace.TRACE_TAG_WINDOW_MANAGER, VISIBLE_TASKS_COUNTER_NAME, @@ -320,7 +335,11 @@ class DesktopModeLoggerTransitionObserver( } } - private fun buildTaskUpdateForTask(taskInfo: TaskInfo, visibleTasks: Int): TaskUpdate { + private fun buildTaskUpdateForTask( + taskInfo: TaskInfo, + visibleTasks: Int, + minimizeReason: MinimizeReason? = null, + ): TaskUpdate { val screenBounds = taskInfo.configuration.windowConfiguration.bounds val positionInParent = taskInfo.positionInParent return TaskUpdate( @@ -331,6 +350,7 @@ class DesktopModeLoggerTransitionObserver( taskX = positionInParent.x, taskY = positionInParent.y, visibleTaskCount = visibleTasks, + minimizeReason = minimizeReason, ) } @@ -384,12 +404,17 @@ class DesktopModeLoggerTransitionObserver( wasPreviousTransitionExitByScreenOff = true ExitReason.SCREEN_OFF } + // TODO(b/384490301): differentiate back gesture / button exit from clicking the close + // button located in the window top corner. + transitionInfo.type == WindowManager.TRANSIT_TO_BACK -> ExitReason.TASK_MOVED_TO_BACK transitionInfo.type == WindowManager.TRANSIT_CLOSE -> ExitReason.TASK_FINISHED transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG -> ExitReason.DRAG_TO_EXIT transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON -> ExitReason.APP_HANDLE_MENU_BUTTON_EXIT + transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT -> ExitReason.KEYBOARD_SHORTCUT_EXIT + transitionInfo.isExitToRecentsTransition() -> ExitReason.RETURN_HOME_OR_OVERVIEW transitionInfo.type == Transitions.TRANSIT_MINIMIZE -> ExitReason.TASK_MINIMIZED else -> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index 606a729305b4..90191345147c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -82,7 +82,7 @@ fun calculateInitialBounds( // For portrait resizeable activities, respect apps fullscreen width but // apply ideal size height. Size( - taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth, + taskInfo.appCompatTaskInfo.topActivityAppBounds.width(), idealSize.height, ) } else { @@ -104,7 +104,7 @@ fun calculateInitialBounds( // apply custom app width. Size( customPortraitWidthForLandscapeApp, - taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight, + taskInfo.appCompatTaskInfo.topActivityAppBounds.height(), ) } else { // For portrait resizeable activities, simply apply ideal size. @@ -196,13 +196,8 @@ fun maximizeSizeGivenAspectRatio( /** Calculates the aspect ratio of an activity from its fullscreen bounds. */ fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float { - val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth - val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight - if (taskInfo.appCompatTaskInfo.isTopActivityLetterboxed || !taskInfo.canChangeAspectRatio) { - return maxOf(appLetterboxWidth, appLetterboxHeight) / - minOf(appLetterboxWidth, appLetterboxHeight).toFloat() - } - val appBounds = taskInfo.configuration.windowConfiguration.appBounds ?: return 1f + if (taskInfo.appCompatTaskInfo.topActivityAppBounds.isEmpty) return 1f + val appBounds = taskInfo.appCompatTaskInfo.topActivityAppBounds return maxOf(appBounds.height(), appBounds.width()) / minOf(appBounds.height(), appBounds.width()).toFloat() } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt index 45faba6e341f..0330a5f0c4e7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt @@ -127,14 +127,20 @@ class DesktopTasksLimiter( override fun onTransitionStarting(transition: IBinder) { val mActiveTaskDetails = activeTransitionTokensAndTasks[transition] - if (mActiveTaskDetails != null && mActiveTaskDetails.transitionInfo != null) { - // Begin minimize window CUJ instrumentation. - interactionJankMonitor.begin( - mActiveTaskDetails.transitionInfo?.rootLeash, - context, - handler, - CUJ_DESKTOP_MODE_MINIMIZE_WINDOW, - ) + val info = mActiveTaskDetails?.transitionInfo ?: return + val minimizeChange = getMinimizeChange(info, mActiveTaskDetails.taskId) ?: return + // Begin minimize window CUJ instrumentation. + interactionJankMonitor.begin( + minimizeChange.leash, + context, + handler, + CUJ_DESKTOP_MODE_MINIMIZE_WINDOW, + ) + } + + private fun getMinimizeChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? { + return info.changes.find { change -> + change.taskInfo?.taskId == taskId && change.mode == TRANSIT_TO_BACK } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java index a611fe1db2ce..c4ff87d175a7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java @@ -74,7 +74,7 @@ public class DragSession { mInitialDragData = data; mInitialDragFlags = dragFlags; displayLayout = dispLayout; - hideDragSourceTaskId = data.getDescription().getExtras() != null + hideDragSourceTaskId = data != null && data.getDescription().getExtras() != null ? data.getDescription().getExtras().getInt(EXTRA_HIDE_DRAG_SOURCE_TASK_ID, -1) : -1; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 27472493a8bc..0519a5e055be 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -89,8 +89,6 @@ public class TaskSnapshotWindow { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId); - final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; - final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters( info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING, snapshot.getHardwareBuffer().getFormat(), appToken); @@ -152,8 +150,8 @@ public class TaskSnapshotWindow { return null; } - SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot, - info.taskBounds, topWindowInsetsState, true /* releaseAfterDraw */); + SnapshotDrawerUtils.drawSnapshotOnSurface(layoutParams, surfaceControl, snapshot, + info.taskBounds, true /* releaseAfterDraw */); snapshotSurface.mHasDrawn = true; snapshotSurface.reportDrawn(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java index 2a22d4dd0cb5..34d1011bac0e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/WindowlessSnapshotWindowCreator.java @@ -26,7 +26,6 @@ import android.content.Context; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.view.Display; -import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.WindowManager; @@ -77,12 +76,11 @@ class WindowlessSnapshotWindowCreator { final SurfaceControlViewHost mViewHost = new SurfaceControlViewHost( mContext, display, wlw, "WindowlessSnapshotWindowCreator"); final Rect windowBounds = runningTaskInfo.configuration.windowConfiguration.getBounds(); - final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; final FrameLayout rootLayout = new FrameLayout( mSplashscreenContentDrawer.createViewContextWrapper(mContext)); mViewHost.setView(rootLayout, lp); - SnapshotDrawerUtils.drawSnapshotOnSurface(info, lp, wlw.mChildSurface, snapshot, - windowBounds, topWindowInsetsState, false /* releaseAfterDraw */); + SnapshotDrawerUtils.drawSnapshotOnSurface(lp, wlw.mChildSurface, snapshot, + windowBounds, false /* releaseAfterDraw */); final ActivityManager.TaskDescription taskDescription = SnapshotDrawerUtils.getOrCreateTaskDescription(runningTaskInfo); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java new file mode 100644 index 000000000000..0d75e659d95c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor; + +import android.app.ActivityManager.RunningTaskInfo; +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.Log; +import android.util.SparseArray; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.SurfaceControl; +import android.view.View; +import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; + +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; +import com.android.wm.shell.shared.FocusTransitionListener; +import com.android.wm.shell.shared.annotations.ShellBackgroundThread; +import com.android.wm.shell.shared.annotations.ShellMainThread; +import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.FocusTransitionObserver; +import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; +import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; + +/** + * Works with decorations that extend {@link CarWindowDecoration}. + */ +public abstract class CarWindowDecorViewModel + implements WindowDecorViewModel, FocusTransitionListener { + private static final String TAG = "CarWindowDecorViewModel"; + + private final ShellTaskOrganizer mTaskOrganizer; + private final Context mContext; + private final @ShellBackgroundThread ShellExecutor mBgExecutor; + private final ShellExecutor mMainExecutor; + private final DisplayController mDisplayController; + private final FocusTransitionObserver mFocusTransitionObserver; + private final SyncTransactionQueue mSyncQueue; + private final SparseArray<CarWindowDecoration> mWindowDecorByTaskId = new SparseArray<>(); + private final WindowDecorViewHostSupplier<WindowDecorViewHost> mWindowDecorViewHostSupplier; + + public CarWindowDecorViewModel( + Context context, + @ShellBackgroundThread ShellExecutor bgExecutor, + @ShellMainThread ShellExecutor shellExecutor, + ShellInit shellInit, + ShellTaskOrganizer taskOrganizer, + DisplayController displayController, + SyncTransactionQueue syncQueue, + FocusTransitionObserver focusTransitionObserver, + WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) { + mContext = context; + mMainExecutor = shellExecutor; + mBgExecutor = bgExecutor; + mTaskOrganizer = taskOrganizer; + mDisplayController = displayController; + mFocusTransitionObserver = focusTransitionObserver; + mSyncQueue = syncQueue; + mWindowDecorViewHostSupplier = windowDecorViewHostSupplier; + + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + mFocusTransitionObserver.setLocalFocusTransitionListener(this, mMainExecutor); + } + + @Override + public void onFocusedTaskChanged(int taskId, boolean isFocusedOnDisplay, + boolean isFocusedGlobally) { + // no-op + } + + @Override + public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) { + // no-op + } + + @Override + public void setSplitScreenController(SplitScreenController splitScreenController) { + // no-op + } + + @Override + public boolean onTaskOpening( + RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + if (!shouldShowWindowDecor(taskInfo)) { + return false; + } + createWindowDecoration(taskInfo, taskSurface, startT, finishT); + return true; + } + + @Override + public void onTaskInfoChanged(RunningTaskInfo taskInfo) { + final CarWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); + + if (decoration == null) { + return; + } + + if (!shouldShowWindowDecor(taskInfo)) { + destroyWindowDecoration(taskInfo); + return; + } + + decoration.relayout(taskInfo, decoration.mHasGlobalFocus, decoration.mExclusionRegion); + } + + @Override + public void onTaskVanished(RunningTaskInfo taskInfo) { + // A task vanishing doesn't necessarily mean the task was closed, it could also mean its + // windowing mode changed. We're only interested in closing tasks so checking whether + // its info still exists in the task organizer is one way to disambiguate. + final boolean closed = mTaskOrganizer.getRunningTaskInfo(taskInfo.taskId) == null; + if (closed) { + // Destroying the window decoration is usually handled when a TRANSIT_CLOSE transition + // changes happen, but there are certain cases in which closing tasks aren't included + // in transitions, such as when a non-visible task is closed. See b/296921167. + // Destroy the decoration here in case the lack of transition missed it. + destroyWindowDecoration(taskInfo); + } + } + + @Override + public void onTaskChanging( + RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + final CarWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); + + if (!shouldShowWindowDecor(taskInfo)) { + if (decoration != null) { + destroyWindowDecoration(taskInfo); + } + return; + } + + if (decoration == null) { + createWindowDecoration(taskInfo, taskSurface, startT, finishT); + } else { + decoration.relayout(taskInfo, startT, finishT); + } + } + + @Override + public void onTaskClosing( + RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + final CarWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); + if (decoration == null) { + return; + } + decoration.relayout(taskInfo, startT, finishT); + } + + @Override + public void destroyWindowDecoration(RunningTaskInfo taskInfo) { + final CarWindowDecoration decoration = + mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId); + if (decoration == null) { + return; + } + + decoration.close(); + } + + /** + * @return {@code true} if the task/activity associated with {@code taskInfo} should show + * window decoration. + */ + protected abstract boolean shouldShowWindowDecor(RunningTaskInfo taskInfo); + + private void createWindowDecoration( + RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + final CarWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId); + if (oldDecoration != null) { + // close the old decoration if it exists to avoid two window decorations being added + oldDecoration.close(); + } + final CarWindowDecoration windowDecoration = + new CarWindowDecoration( + mContext, + mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */), + mDisplayController, + mTaskOrganizer, + taskInfo, + taskSurface, + mBgExecutor, + mWindowDecorViewHostSupplier, + new ButtonClickListener(taskInfo)); + mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); + windowDecoration.relayout(taskInfo, startT, finishT); + } + + private class ButtonClickListener implements View.OnClickListener { + private final WindowContainerToken mTaskToken; + private final int mDisplayId; + + private ButtonClickListener(RunningTaskInfo taskInfo) { + mTaskToken = taskInfo.token; + mDisplayId = taskInfo.displayId; + } + + @Override + public void onClick(View v) { + final int id = v.getId(); + if (id == R.id.close_window) { + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.removeTask(mTaskToken); + mSyncQueue.queue(wct); + } else if (id == R.id.back_button) { + sendBackEvent(KeyEvent.ACTION_DOWN, mDisplayId); + sendBackEvent(KeyEvent.ACTION_UP, mDisplayId); + } + } + + private void sendBackEvent(int action, int displayId) { + final long when = SystemClock.uptimeMillis(); + final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK, + 0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, + 0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, + InputDevice.SOURCE_KEYBOARD); + + ev.setDisplayId(displayId); + if (!mContext.getSystemService(InputManager.class) + .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) { + Log.e(TAG, "Inject input event fail"); + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java new file mode 100644 index 000000000000..1ca82d23c830 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor; + +import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.content.Context; +import android.graphics.Rect; +import android.graphics.Region; +import android.view.InsetsState; +import android.view.SurfaceControl; +import android.view.View; +import android.window.WindowContainerTransaction; + +import androidx.annotation.NonNull; + +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.shared.annotations.ShellBackgroundThread; +import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; +import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; + +/** + * {@link WindowDecoration} to show app controls for windows on automotive. + */ +public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { + private WindowDecorLinearLayout mRootView; + private @ShellBackgroundThread final ShellExecutor mBgExecutor; + private final View.OnClickListener mClickListener; + + CarWindowDecoration( + Context context, + @android.annotation.NonNull Context userContext, + DisplayController displayController, + ShellTaskOrganizer taskOrganizer, + ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + @ShellBackgroundThread ShellExecutor bgExecutor, + WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier, + View.OnClickListener clickListener) { + super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, + windowDecorViewHostSupplier); + mBgExecutor = bgExecutor; + mClickListener = clickListener; + } + + @Override + void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus, + @NonNull Region displayExclusionRegion) { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + relayout(taskInfo, t, t); + } + + @SuppressLint("MissingPermission") + void relayout(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + + RelayoutParams relayoutParams = new RelayoutParams(); + RelayoutResult<WindowDecorLinearLayout> outResult = new RelayoutResult<>(); + + updateRelayoutParams(relayoutParams, taskInfo, + mDisplayController.getInsetsState(taskInfo.displayId)); + + relayout(relayoutParams, startT, finishT, wct, mRootView, outResult); + // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo + mBgExecutor.execute(() -> mTaskOrganizer.applyTransaction(wct)); + + if (outResult.mRootView == null) { + // This means something blocks the window decor from showing, e.g. the task is hidden. + // Nothing is set up in this case including the decoration surface. + return; + } + if (mRootView != outResult.mRootView) { + mRootView = outResult.mRootView; + setupRootView(outResult.mRootView, mClickListener); + } + } + + @Override + @NonNull + Rect calculateValidDragArea() { + return new Rect(); + } + + @Override + int getCaptionViewId() { + return R.id.caption; + } + + private void updateRelayoutParams( + RelayoutParams relayoutParams, + ActivityManager.RunningTaskInfo taskInfo, + InsetsState displayInsetsState) { + relayoutParams.reset(); + relayoutParams.mRunningTaskInfo = taskInfo; + // todo(b/382071404): update to car specific UI + relayoutParams.mLayoutResId = R.layout.caption_window_decor; + relayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; + relayoutParams.mIsCaptionVisible = mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded; + relayoutParams.mCaptionTopPadding = 0; + relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; + relayoutParams.mApplyStartTransactionOnDraw = true; + } + + /** + * Sets up listeners when a new root view is created. + */ + private void setupRootView(View rootView, View.OnClickListener onClickListener) { + final View caption = rootView.findViewById(R.id.caption); + final View close = caption.findViewById(R.id.close_window); + if (close != null) { + close.setOnClickListener(onClickListener); + } + final View back = caption.findViewById(R.id.back_button); + if (back != null) { + back.setOnClickListener(onClickListener); + } + } +} 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 7928e5ed4188..a7a5f09c88f8 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 @@ -935,10 +935,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // back to the decoration using // {@link DesktopModeWindowDecoration#setOnMaximizeOrRestoreClickListener}, which // should shared with the maximize menu's maximize/restore actions. + final DesktopRepository desktopRepository = mDesktopUserRepositories.getProfile( + decoration.mTaskInfo.userId); if (Flags.enableFullyImmersiveInDesktop() - && TaskInfoKt.getRequestingImmersive(decoration.mTaskInfo)) { - // Task is requesting immersive, so it should either enter or exit immersive, - // depending on immersive state. + && desktopRepository.isTaskInFullImmersiveState( + decoration.mTaskInfo.taskId)) { + // Task is in immersive and should exit. onEnterOrExitImmersive(decoration.mTaskInfo); } else { // Full immersive is disabled or task doesn't request/support it, so just diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt index 9972247df46d..ab1ac1a0efa3 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt @@ -44,6 +44,7 @@ import android.tools.flicker.assertors.assertions.AppWindowOnTopAtStart import android.tools.flicker.assertors.assertions.AppWindowRemainInsideDisplayBounds import android.tools.flicker.assertors.assertions.AppWindowReturnsToStartBoundsAndPosition import android.tools.flicker.assertors.assertions.LauncherWindowReplacesAppAsTopWindow +import android.tools.flicker.assertors.assertions.VisibleLayersShownMoreThanOneConsecutiveEntry import android.tools.flicker.config.AssertionTemplates import android.tools.flicker.config.FlickerConfigEntry import android.tools.flicker.config.ScenarioId @@ -463,7 +464,9 @@ class DesktopModeFlickerScenarios { } ), assertions = - AssertionTemplates.COMMON_ASSERTIONS + + AssertionTemplates.COMMON_ASSERTIONS.toMutableMap().also { + it.remove(VisibleLayersShownMoreThanOneConsecutiveEntry()) + } + listOf( AppWindowOnTopAtStart(DESKTOP_MODE_APP), AppWindowBecomesInvisible(DESKTOP_MODE_APP), @@ -489,7 +492,9 @@ class DesktopModeFlickerScenarios { } ), assertions = - AssertionTemplates.COMMON_ASSERTIONS + + AssertionTemplates.COMMON_ASSERTIONS.toMutableMap().also { + it.remove(VisibleLayersShownMoreThanOneConsecutiveEntry()) + } + listOf( AppWindowOnTopAtStart(DESKTOP_MODE_APP), AppWindowBecomesInvisible(DESKTOP_MODE_APP), diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAppsWithKeyboard.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAppsWithKeyboard.kt new file mode 100644 index 000000000000..56f1dcbf838c --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MinimizeAppsWithKeyboard.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker + +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MINIMIZE_APP +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MINIMIZE_LAST_APP +import com.android.wm.shell.scenarios.MinimizeAppWindows +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Minimize app windows by pressing META + -. + * + * Assert that the app windows gets hidden. + */ +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class MinimizeAppsWithKeyboard : MinimizeAppWindows(usingKeyboard = true) { + @ExpectedScenarios(["MINIMIZE_APP", "MINIMIZE_LAST_APP"]) + @Test + override fun minimizeAllAppWindows() = super.minimizeAllAppWindows() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(MINIMIZE_APP) + .use(MINIMIZE_LAST_APP) + } +} diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt index 971637b62604..835559cd0936 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt @@ -43,7 +43,10 @@ import org.junit.Test */ @Ignore("Test Base Class") abstract class MinimizeAppWindows -constructor(private val rotation: Rotation = Rotation.ROTATION_0) { +constructor( + private val rotation: Rotation = Rotation.ROTATION_0, + private val usingKeyboard: Boolean = false +) { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val tapl = LauncherInstrumentation() private val wmHelper = WindowManagerStateHelper(instrumentation) @@ -68,9 +71,9 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0) { @Test open fun minimizeAllAppWindows() { - testApp3.minimizeDesktopApp(wmHelper, device) - testApp2.minimizeDesktopApp(wmHelper, device) - testApp1.minimizeDesktopApp(wmHelper, device) + testApp3.minimizeDesktopApp(wmHelper, device, usingKeyboard = usingKeyboard) + testApp2.minimizeDesktopApp(wmHelper, device, usingKeyboard = usingKeyboard) + testApp1.minimizeDesktopApp(wmHelper, device, usingKeyboard = usingKeyboard) } @After 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 abd707817621..c0ff2f0652b3 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 @@ -45,6 +45,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_M import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_UNMINIMIZE_REASON import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test @@ -77,6 +78,12 @@ class DesktopModeEventLoggerTest : ShellTestCase() { doReturn(DISPLAY_HEIGHT).whenever(displayLayout).height() } + @After + fun tearDown() { + clearInvocations(staticMockMarker(FrameworkStatsLog::class.java)) + clearInvocations(staticMockMarker(EventLogTags::class.java)) + } + @Test fun logSessionEnter_logsEnterReasonWithNewSessionId() { desktopModeEventLogger.logSessionEnter(EnterReason.KEYBOARD_SHORTCUT_ENTER) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt index 43684fb92b64..9d410137fc4a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt @@ -46,6 +46,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON @@ -508,6 +509,20 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { } @Test + fun transitExitBackGesture_logTaskRemovedAndExitReasonTaskMovedToBack() { + // add a freeform task + transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM)) + transitionObserver.isSessionActive = true + + // task moved to back + val change = createChange(TRANSIT_TO_BACK, createTaskInfo(WINDOWING_MODE_FREEFORM)) + val transitionInfo = TransitionInfoBuilder(TRANSIT_TO_BACK).addChange(change).build() + callOnTransitionReady(transitionInfo) + + verifyTaskRemovedAndExitLogging(ExitReason.TASK_MOVED_TO_BACK, DEFAULT_TASK_UPDATE) + } + + @Test fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown() { // add a freeform task transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM)) @@ -566,7 +581,10 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { assertFalse(transitionObserver.isSessionActive) verify(desktopModeEventLogger, times(1)).logSessionExit(eq(ExitReason.TASK_MINIMIZED)) - verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(DEFAULT_TASK_UPDATE)) + verify(desktopModeEventLogger, times(1)) + .logTaskRemoved( + eq(DEFAULT_TASK_UPDATE.copy(minimizeReason = MinimizeReason.MINIMIZE_BUTTON)) + ) verifyZeroInteractions(desktopModeEventLogger) } 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 4f37180baa37..e1c2153014fa 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 @@ -4160,8 +4160,7 @@ class DesktopTasksControllerTest : ShellTestCase() { screenOrientation = SCREEN_ORIENTATION_LANDSCAPE configuration.windowConfiguration.appBounds = bounds } - appCompatTaskInfo.topActivityLetterboxAppWidth = bounds.width() - appCompatTaskInfo.topActivityLetterboxAppHeight = bounds.height() + appCompatTaskInfo.topActivityAppBounds.set(0, 0, bounds.width(), bounds.height()) isResizeable = false } @@ -4879,15 +4878,19 @@ class DesktopTasksControllerTest : ShellTestCase() { appCompatTaskInfo.isSystemFullscreenOverrideEnabled = enableSystemFullscreenOverride if (deviceOrientation == ORIENTATION_LANDSCAPE) { - configuration.windowConfiguration.appBounds = - Rect(0, 0, DISPLAY_DIMENSION_LONG, DISPLAY_DIMENSION_SHORT) - appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_LONG - appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_SHORT + appCompatTaskInfo.topActivityAppBounds.set( + 0, + 0, + DISPLAY_DIMENSION_LONG, + DISPLAY_DIMENSION_SHORT, + ) } else { - configuration.windowConfiguration.appBounds = - Rect(0, 0, DISPLAY_DIMENSION_SHORT, DISPLAY_DIMENSION_LONG) - appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_SHORT - appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_LONG + appCompatTaskInfo.topActivityAppBounds.set( + 0, + 0, + DISPLAY_DIMENSION_SHORT, + DISPLAY_DIMENSION_LONG, + ) } if (shouldLetterbox) { @@ -4897,17 +4900,15 @@ class DesktopTasksControllerTest : ShellTestCase() { screenOrientation == SCREEN_ORIENTATION_PORTRAIT ) { // Letterbox to portrait size - appCompatTaskInfo.setTopActivityLetterboxed(true) - appCompatTaskInfo.topActivityLetterboxAppWidth = 1200 - appCompatTaskInfo.topActivityLetterboxAppHeight = 1600 + appCompatTaskInfo.isTopActivityLetterboxed = true + appCompatTaskInfo.topActivityAppBounds.set(0, 0, 1200, 1600) } else if ( deviceOrientation == ORIENTATION_PORTRAIT && screenOrientation == SCREEN_ORIENTATION_LANDSCAPE ) { // Letterbox to landscape size - appCompatTaskInfo.setTopActivityLetterboxed(true) - appCompatTaskInfo.topActivityLetterboxAppWidth = 1600 - appCompatTaskInfo.topActivityLetterboxAppHeight = 1200 + appCompatTaskInfo.isTopActivityLetterboxed = true + appCompatTaskInfo.topActivityAppBounds.set(0, 0, 1600, 1200) } } } 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 e6f1fcf7f14f..52602f22fd4b 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 @@ -551,7 +551,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { .getTransitionObserver() .onTransitionReady( transition, - TransitionInfoBuilder(TRANSIT_OPEN).build(), + TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), StubTransaction() /* startTransaction */, StubTransaction(), /* finishTransaction */ ) @@ -583,7 +583,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { .getTransitionObserver() .onTransitionReady( transition, - TransitionInfoBuilder(TRANSIT_OPEN).build(), + TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), StubTransaction() /* startTransaction */, StubTransaction(), /* finishTransaction */ ) @@ -616,7 +616,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { .getTransitionObserver() .onTransitionReady( mergedTransition, - TransitionInfoBuilder(TRANSIT_OPEN).build(), + TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(), StubTransaction() /* startTransaction */, StubTransaction(), /* finishTransaction */ ) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragSessionTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragSessionTest.kt index 3d59342f62d8..8ccca07142aa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragSessionTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragSessionTest.kt @@ -59,6 +59,13 @@ class DragSessionTest : ShellTestCase() { } @Test + fun testNullClipData() { + // Start a new drag session with null data + val session = DragSession(activityTaskManager, displayLayout, null, 0) + assertThat(session.hideDragSourceTaskId).isEqualTo(-1) + } + + @Test fun testGetRunningTask() { // Set up running tasks val runningTasks = listOf( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index ce482cdd9944..4b01d841b824 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -55,7 +55,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.UserHandle; import android.testing.TestableContext; -import android.view.InsetsState; import android.view.Surface; import android.view.WindowManager; import android.view.WindowMetrics; @@ -338,9 +337,7 @@ public class StartingSurfaceDrawerTests extends ShellTestCase { windowInfo.appToken = appToken; windowInfo.targetActivityInfo = info; windowInfo.taskInfo = taskInfo; - windowInfo.topOpaqueWindowInsetsState = new InsetsState(); windowInfo.mainWindowLayoutParams = new WindowManager.LayoutParams(); - windowInfo.topOpaqueWindowLayoutParams = new WindowManager.LayoutParams(); return windowInfo; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index aead0a7afb53..ffe8e7135513 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -1054,26 +1054,6 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) - fun testImmersiveButtonClick_entersImmersiveMode() { - val onClickListenerCaptor = forClass(View.OnClickListener::class.java) - as ArgumentCaptor<View.OnClickListener> - val decor = createOpenTaskDecoration( - windowingMode = WINDOWING_MODE_FREEFORM, - onCaptionButtonClickListener = onClickListenerCaptor, - requestingImmersive = true, - ) - val view = mock(View::class.java) - whenever(view.id).thenReturn(R.id.maximize_window) - whenever(mockDesktopRepository.isTaskInFullImmersiveState(decor.mTaskInfo.taskId)) - .thenReturn(false) - - onClickListenerCaptor.value.onClick(view) - - verify(mockDesktopImmersiveController).moveTaskToImmersive(decor.mTaskInfo) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun testImmersiveRestoreButtonClick_exitsImmersiveMode() { val onClickListenerCaptor = forClass(View.OnClickListener::class.java) as ArgumentCaptor<View.OnClickListener> diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 1bc15d72bacc..cc4a29b31996 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -199,6 +199,7 @@ cc_test { // This is to suppress warnings/errors from gtest "-Wno-unnamed-type-template-args", ], + require_root: true, srcs: [ // Helpers/infra for testing. "tests/CommonHelpers.cpp", diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index e6182454ad8a..5955915c9fcd 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -1420,18 +1420,20 @@ void AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo Mutex AssetManager::SharedZip::gLock; DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen; -AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) - : mPath(path), mZipFile(NULL), mModWhen(modWhen), - mResourceTableAsset(NULL), mResourceTable(NULL) -{ - if (kIsDebug) { - ALOGI("Creating SharedZip %p %s\n", this, mPath.c_str()); - } - ALOGV("+++ opening zip '%s'\n", mPath.c_str()); - mZipFile = ZipFileRO::open(mPath.c_str()); - if (mZipFile == NULL) { - ALOGD("failed to open Zip archive '%s'\n", mPath.c_str()); - } +AssetManager::SharedZip::SharedZip(const String8& path, ModDate modWhen) + : mPath(path), + mZipFile(NULL), + mModWhen(modWhen), + mResourceTableAsset(NULL), + mResourceTable(NULL) { + if (kIsDebug) { + ALOGI("Creating SharedZip %p %s\n", this, mPath.c_str()); + } + ALOGV("+++ opening zip '%s'\n", mPath.c_str()); + mZipFile = ZipFileRO::open(mPath.c_str()); + if (mZipFile == NULL) { + ALOGD("failed to open Zip archive '%s'\n", mPath.c_str()); + } } AssetManager::SharedZip::SharedZip(int fd, const String8& path) @@ -1453,7 +1455,7 @@ sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path, bool createIfNotPresent) { AutoMutex _l(gLock); - time_t modWhen = getFileModDate(path.c_str()); + auto modWhen = getFileModDate(path.c_str()); sp<SharedZip> zip = gOpen.valueFor(path).promote(); if (zip != NULL && zip->mModWhen == modWhen) { return zip; @@ -1520,8 +1522,8 @@ ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res) bool AssetManager::SharedZip::isUpToDate() { - time_t modWhen = getFileModDate(mPath.c_str()); - return mModWhen == modWhen; + auto modWhen = getFileModDate(mPath.c_str()); + return mModWhen == modWhen; } void AssetManager::SharedZip::addOverlay(const asset_path& ap) diff --git a/libs/androidfw/TypeWrappers.cpp b/libs/androidfw/TypeWrappers.cpp index 70d14a11830e..970463492c1a 100644 --- a/libs/androidfw/TypeWrappers.cpp +++ b/libs/androidfw/TypeWrappers.cpp @@ -16,8 +16,6 @@ #include <androidfw/TypeWrappers.h> -#include <algorithm> - namespace android { TypeVariant::TypeVariant(const ResTable_type* data) : data(data), mLength(dtohl(data->entryCount)) { @@ -31,30 +29,44 @@ TypeVariant::TypeVariant(const ResTable_type* data) : data(data), mLength(dtohl( ALOGE("Type's entry indices extend beyond its boundaries"); mLength = 0; } else { - mLength = ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx + 1; + mLength = dtohs(ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx) + 1; } } } TypeVariant::iterator& TypeVariant::iterator::operator++() { - mIndex++; + ++mIndex; if (mIndex > mTypeVariant->mLength) { mIndex = mTypeVariant->mLength; } - return *this; -} -static bool keyCompare(uint32_t entry, uint16_t index) { - return dtohs(ResTable_sparseTypeEntry{entry}.idx) < index; + const ResTable_type* type = mTypeVariant->data; + if ((type->flags & ResTable_type::FLAG_SPARSE) == 0) { + return *this; + } + + // Need to adjust |mSparseIndex| as well if we've passed its current element. + const uint32_t entryCount = dtohl(type->entryCount); + const auto entryIndices = reinterpret_cast<const uint32_t*>( + reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize)); + if (mSparseIndex >= entryCount) { + return *this; // done + } + const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex); + if (mIndex > dtohs(element->idx)) { + ++mSparseIndex; + } + + return *this; } const ResTable_entry* TypeVariant::iterator::operator*() const { - const ResTable_type* type = mTypeVariant->data; if (mIndex >= mTypeVariant->mLength) { - return NULL; + return nullptr; } - const uint32_t entryCount = dtohl(mTypeVariant->data->entryCount); + const ResTable_type* type = mTypeVariant->data; + const uint32_t entryCount = dtohl(type->entryCount); const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type) + dtohl(type->header.size); const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>( @@ -63,18 +75,19 @@ const ResTable_entry* TypeVariant::iterator::operator*() const { sizeof(uint16_t) : sizeof(uint32_t); if (reinterpret_cast<uintptr_t>(entryIndices) + (indexSize * entryCount) > containerEnd) { ALOGE("Type's entry indices extend beyond its boundaries"); - return NULL; + return nullptr; } uint32_t entryOffset; if (type->flags & ResTable_type::FLAG_SPARSE) { - auto iter = std::lower_bound(entryIndices, entryIndices + entryCount, mIndex, keyCompare); - if (iter == entryIndices + entryCount - || dtohs(ResTable_sparseTypeEntry{*iter}.idx) != mIndex) { - return NULL; + if (mSparseIndex >= entryCount) { + return nullptr; } - - entryOffset = static_cast<uint32_t>(dtohs(ResTable_sparseTypeEntry{*iter}.offset)) * 4u; + const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex); + if (dtohs(element->idx) != mIndex) { + return nullptr; + } + entryOffset = static_cast<uint32_t>(dtohs(element->offset)) * 4u; } else if (type->flags & ResTable_type::FLAG_OFFSET16) { auto entryIndices16 = reinterpret_cast<const uint16_t*>(entryIndices); entryOffset = offset_from16(entryIndices16[mIndex]); @@ -83,25 +96,25 @@ const ResTable_entry* TypeVariant::iterator::operator*() const { } if (entryOffset == ResTable_type::NO_ENTRY) { - return NULL; + return nullptr; } if ((entryOffset & 0x3) != 0) { ALOGE("Index %u points to entry with unaligned offset 0x%08x", mIndex, entryOffset); - return NULL; + return nullptr; } const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>( reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset); if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) { ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex); - return NULL; + return nullptr; } else if (reinterpret_cast<uintptr_t>(entry) + entry->size() > containerEnd) { ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex); - return NULL; + return nullptr; } else if (entry->size() < sizeof(*entry)) { ALOGE("Entry at index %u is too small (%zu)", mIndex, entry->size()); - return NULL; + return nullptr; } return entry; } diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index ce0985b38986..376c881ea376 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -280,21 +280,21 @@ private: ~SharedZip(); private: - SharedZip(const String8& path, time_t modWhen); - SharedZip(int fd, const String8& path); - SharedZip(); // <-- not implemented + SharedZip(const String8& path, ModDate modWhen); + SharedZip(int fd, const String8& path); + SharedZip(); // <-- not implemented - String8 mPath; - ZipFileRO* mZipFile; - time_t mModWhen; + String8 mPath; + ZipFileRO* mZipFile; + ModDate mModWhen; - Asset* mResourceTableAsset; - ResTable* mResourceTable; + Asset* mResourceTableAsset; + ResTable* mResourceTable; - Vector<asset_path> mOverlays; + Vector<asset_path> mOverlays; - static Mutex gLock; - static DefaultKeyedVector<String8, wp<SharedZip> > gOpen; + static Mutex gLock; + static DefaultKeyedVector<String8, wp<SharedZip> > gOpen; }; /* diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index e213fbd22ab0..ac75eb3bb98c 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -25,8 +25,9 @@ #include "android-base/macros.h" #include "android-base/unique_fd.h" #include "androidfw/ConfigDescription.h" -#include "androidfw/StringPiece.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/StringPiece.h" +#include "androidfw/misc.h" #include "utils/ByteOrder.h" namespace android { @@ -213,7 +214,7 @@ class LoadedIdmap { android::base::unique_fd idmap_fd_; std::string_view overlay_apk_path_; std::string_view target_apk_path_; - time_t idmap_last_mod_time_; + ModDate idmap_last_mod_time_; private: DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); diff --git a/libs/androidfw/include/androidfw/TypeWrappers.h b/libs/androidfw/include/androidfw/TypeWrappers.h index fb2fad619011..db641b78a4e4 100644 --- a/libs/androidfw/include/androidfw/TypeWrappers.h +++ b/libs/androidfw/include/androidfw/TypeWrappers.h @@ -27,24 +27,14 @@ struct TypeVariant { class iterator { public: - iterator& operator=(const iterator& rhs) { - mTypeVariant = rhs.mTypeVariant; - mIndex = rhs.mIndex; - return *this; - } - bool operator==(const iterator& rhs) const { return mTypeVariant == rhs.mTypeVariant && mIndex == rhs.mIndex; } - bool operator!=(const iterator& rhs) const { - return mTypeVariant != rhs.mTypeVariant || mIndex != rhs.mIndex; - } - iterator operator++(int) { - uint32_t prevIndex = mIndex; + iterator prev = *this; operator++(); - return iterator(mTypeVariant, prevIndex); + return prev; } const ResTable_entry* operator->() const { @@ -60,18 +50,26 @@ struct TypeVariant { private: friend struct TypeVariant; - iterator(const TypeVariant* tv, uint32_t index) - : mTypeVariant(tv), mIndex(index) {} + + enum class Kind { Begin, End }; + iterator(const TypeVariant* tv, Kind kind) + : mTypeVariant(tv) { + mSparseIndex = mIndex = kind == Kind::Begin ? 0 : tv->mLength; + // mSparseIndex here is technically past the number of sparse entries, but it is still + // ok as it is enough to infer that this is the end iterator. + } + const TypeVariant* mTypeVariant; uint32_t mIndex; + uint32_t mSparseIndex; }; iterator beginEntries() const { - return iterator(this, 0); + return iterator(this, iterator::Kind::Begin); } iterator endEntries() const { - return iterator(this, mLength); + return iterator(this, iterator::Kind::End); } const ResTable_type* data; diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h index 077609d20d55..c9ba8a01a5e9 100644 --- a/libs/androidfw/include/androidfw/misc.h +++ b/libs/androidfw/include/androidfw/misc.h @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#include <sys/types.h> +#include <time.h> // // Handy utility functions and portability code. // -#ifndef _LIBS_ANDROID_FW_MISC_H -#define _LIBS_ANDROID_FW_MISC_H namespace android { @@ -41,15 +40,35 @@ typedef enum FileType { } FileType; /* get the file's type; follows symlinks */ FileType getFileType(const char* fileName); -/* get the file's modification date; returns -1 w/errno set on failure */ -time_t getFileModDate(const char* fileName); + +// MinGW doesn't support nanosecond resolution in stat() modification time, and given +// that it only matters on the device it's ok to keep it at a seconds level there. +#ifdef _WIN32 +using ModDate = time_t; +inline constexpr ModDate kInvalidModDate = ModDate(-1); +inline constexpr unsigned long long kModDateResolutionNs = 1ull * 1000 * 1000 * 1000; +inline time_t toTimeT(ModDate m) { + return m; +} +#else +using ModDate = timespec; +inline constexpr ModDate kInvalidModDate = {-1, -1}; +inline constexpr unsigned long long kModDateResolutionNs = 1; +inline time_t toTimeT(ModDate m) { + return m.tv_sec; +} +#endif + +/* get the file's modification date; returns kInvalidModDate w/errno set on failure */ +ModDate getFileModDate(const char* fileName); /* same, but also returns -1 if the file has already been deleted */ -time_t getFileModDate(int fd); +ModDate getFileModDate(int fd); // Check if |path| or |fd| resides on a readonly filesystem. bool isReadonlyFilesystem(const char* path); bool isReadonlyFilesystem(int fd); -}; // namespace android +} // namespace android -#endif // _LIBS_ANDROID_FW_MISC_H +// Whoever uses getFileModDate() will need this as well +bool operator==(const timespec& l, const timespec& r); diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp index 93dcaf549a90..32f3624a3aee 100644 --- a/libs/androidfw/misc.cpp +++ b/libs/androidfw/misc.cpp @@ -28,11 +28,13 @@ #include <sys/vfs.h> #endif // __linux__ -#include <cstring> -#include <cstdio> #include <errno.h> #include <sys/stat.h> +#include <cstdio> +#include <cstring> +#include <tuple> + namespace android { /* @@ -73,27 +75,34 @@ FileType getFileType(const char* fileName) } } -/* - * Get a file's modification date. - */ -time_t getFileModDate(const char* fileName) { - struct stat sb; - if (stat(fileName, &sb) < 0) { - return (time_t)-1; - } - return sb.st_mtime; +static ModDate getModDate(const struct stat& st) { +#ifdef _WIN32 + return st.st_mtime; +#elif defined(__APPLE__) + return st.st_mtimespec; +#else + return st.st_mtim; +#endif } -time_t getFileModDate(int fd) { - struct stat sb; - if (fstat(fd, &sb) < 0) { - return (time_t)-1; - } - if (sb.st_nlink <= 0) { - errno = ENOENT; - return (time_t)-1; - } - return sb.st_mtime; +ModDate getFileModDate(const char* fileName) { + struct stat sb; + if (stat(fileName, &sb) < 0) { + return kInvalidModDate; + } + return getModDate(sb); +} + +ModDate getFileModDate(int fd) { + struct stat sb; + if (fstat(fd, &sb) < 0) { + return kInvalidModDate; + } + if (sb.st_nlink <= 0) { + errno = ENOENT; + return kInvalidModDate; + } + return getModDate(sb); } #ifndef __linux__ @@ -124,4 +133,8 @@ bool isReadonlyFilesystem(int fd) { } #endif // __linux__ -}; // namespace android +} // namespace android + +bool operator==(const timespec& l, const timespec& r) { + return std::tie(l.tv_sec, l.tv_nsec) == std::tie(r.tv_sec, l.tv_nsec); +} diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index 60aa7d88925d..cb2e56f5f5e4 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include <chrono> +#include <thread> + #include "android-base/file.h" #include "androidfw/ApkAssets.h" #include "androidfw/AssetManager2.h" @@ -27,6 +30,7 @@ #include "data/overlayable/R.h" #include "data/system/R.h" +using namespace std::chrono_literals; using ::testing::NotNull; namespace overlay = com::android::overlay; @@ -218,10 +222,13 @@ TEST_F(IdmapTest, OverlayAssetsIsUpToDate) { unlink(temp_file.path); ASSERT_FALSE(apk_assets->IsUpToDate()); - sleep(2); + + const auto sleep_duration = + std::chrono::nanoseconds(std::max(kModDateResolutionNs, 1'000'000ull)); + std::this_thread::sleep_for(sleep_duration); base::WriteStringToFile("hello", temp_file.path); - sleep(2); + std::this_thread::sleep_for(sleep_duration); ASSERT_FALSE(apk_assets->IsUpToDate()); } diff --git a/libs/androidfw/tests/TypeWrappers_test.cpp b/libs/androidfw/tests/TypeWrappers_test.cpp index ed30904ec179..d66e05805484 100644 --- a/libs/androidfw/tests/TypeWrappers_test.cpp +++ b/libs/androidfw/tests/TypeWrappers_test.cpp @@ -14,28 +14,42 @@ * limitations under the License. */ -#include <algorithm> #include <androidfw/ResourceTypes.h> #include <androidfw/TypeWrappers.h> -#include <utils/String8.h> +#include <androidfw/Util.h> + +#include <optional> +#include <vector> #include <gtest/gtest.h> namespace android { -// create a ResTable_type in memory with a vector of Res_value* -static ResTable_type* createTypeTable(std::vector<Res_value*>& values, - bool compact_entry = false, - bool short_offsets = false) +using ResValueVector = std::vector<std::optional<Res_value>>; + +// create a ResTable_type in memory +static util::unique_cptr<ResTable_type> createTypeTable( + const ResValueVector& in_values, bool compact_entry, bool short_offsets, bool sparse) { + ResValueVector sparse_values; + if (sparse) { + std::ranges::copy_if(in_values, std::back_inserter(sparse_values), + [](auto&& v) { return v.has_value(); }); + } + const ResValueVector& values = sparse ? sparse_values : in_values; + ResTable_type t{}; t.header.type = RES_TABLE_TYPE_TYPE; t.header.headerSize = sizeof(t); t.header.size = sizeof(t); t.id = 1; - t.flags = short_offsets ? ResTable_type::FLAG_OFFSET16 : 0; + t.flags = sparse + ? ResTable_type::FLAG_SPARSE + : short_offsets ? ResTable_type::FLAG_OFFSET16 : 0; - t.header.size += values.size() * (short_offsets ? sizeof(uint16_t) : sizeof(uint32_t)); + t.header.size += values.size() * + (sparse ? sizeof(ResTable_sparseTypeEntry) : + short_offsets ? sizeof(uint16_t) : sizeof(uint32_t)); t.entriesStart = t.header.size; t.entryCount = values.size(); @@ -53,9 +67,18 @@ static ResTable_type* createTypeTable(std::vector<Res_value*>& values, memcpy(p_header, &t, sizeof(t)); size_t i = 0, entry_offset = 0; - uint32_t k = 0; - for (auto const& v : values) { - if (short_offsets) { + uint32_t sparse_index = 0; + + for (auto const& v : in_values) { + if (sparse) { + if (!v) { + ++i; + continue; + } + const auto p = reinterpret_cast<ResTable_sparseTypeEntry*>(p_offsets) + sparse_index++; + p->idx = i; + p->offset = (entry_offset >> 2) & 0xffffu; + } else if (short_offsets) { uint16_t *p = reinterpret_cast<uint16_t *>(p_offsets) + i; *p = v ? (entry_offset >> 2) & 0xffffu : 0xffffu; } else { @@ -83,62 +106,92 @@ static ResTable_type* createTypeTable(std::vector<Res_value*>& values, } i++; } - return reinterpret_cast<ResTable_type*>(data); + return util::unique_cptr<ResTable_type>{reinterpret_cast<ResTable_type*>(data)}; } TEST(TypeVariantIteratorTest, shouldIterateOverTypeWithoutErrors) { - std::vector<Res_value *> values; - - Res_value *v1 = new Res_value{}; - values.push_back(v1); - - values.push_back(nullptr); - - Res_value *v2 = new Res_value{}; - values.push_back(v2); - - Res_value *v3 = new Res_value{ sizeof(Res_value), 0, Res_value::TYPE_STRING, 0x12345678}; - values.push_back(v3); + ResValueVector values; + + values.push_back(std::nullopt); + values.push_back(Res_value{}); + values.push_back(std::nullopt); + values.push_back(Res_value{}); + values.push_back(Res_value{ sizeof(Res_value), 0, Res_value::TYPE_STRING, 0x12345678}); + values.push_back(std::nullopt); + values.push_back(std::nullopt); + values.push_back(std::nullopt); + values.push_back(Res_value{ sizeof(Res_value), 0, Res_value::TYPE_STRING, 0x87654321}); // test for combinations of compact_entry and short_offsets - for (size_t i = 0; i < 4; i++) { - bool compact_entry = i & 0x1, short_offsets = i & 0x2; - ResTable_type* data = createTypeTable(values, compact_entry, short_offsets); - TypeVariant v(data); + for (size_t i = 0; i < 8; i++) { + bool compact_entry = i & 0x1, short_offsets = i & 0x2, sparse = i & 0x4; + auto data = createTypeTable(values, compact_entry, short_offsets, sparse); + TypeVariant v(data.get()); TypeVariant::iterator iter = v.beginEntries(); ASSERT_EQ(uint32_t(0), iter.index()); - ASSERT_TRUE(NULL != *iter); - ASSERT_EQ(uint32_t(0), iter->key()); + ASSERT_TRUE(NULL == *iter); ASSERT_NE(v.endEntries(), iter); - iter++; + ++iter; ASSERT_EQ(uint32_t(1), iter.index()); - ASSERT_TRUE(NULL == *iter); + ASSERT_TRUE(NULL != *iter); + ASSERT_EQ(uint32_t(1), iter->key()); ASSERT_NE(v.endEntries(), iter); iter++; ASSERT_EQ(uint32_t(2), iter.index()); + ASSERT_TRUE(NULL == *iter); + ASSERT_NE(v.endEntries(), iter); + + ++iter; + + ASSERT_EQ(uint32_t(3), iter.index()); ASSERT_TRUE(NULL != *iter); - ASSERT_EQ(uint32_t(2), iter->key()); + ASSERT_EQ(uint32_t(3), iter->key()); ASSERT_NE(v.endEntries(), iter); iter++; - ASSERT_EQ(uint32_t(3), iter.index()); + ASSERT_EQ(uint32_t(4), iter.index()); ASSERT_TRUE(NULL != *iter); ASSERT_EQ(iter->is_compact(), compact_entry); - ASSERT_EQ(uint32_t(3), iter->key()); + ASSERT_EQ(uint32_t(4), iter->key()); ASSERT_EQ(uint32_t(0x12345678), iter->value().data); ASSERT_EQ(Res_value::TYPE_STRING, iter->value().dataType); + ++iter; + + ASSERT_EQ(uint32_t(5), iter.index()); + ASSERT_TRUE(NULL == *iter); + ASSERT_NE(v.endEntries(), iter); + + ++iter; + + ASSERT_EQ(uint32_t(6), iter.index()); + ASSERT_TRUE(NULL == *iter); + ASSERT_NE(v.endEntries(), iter); + + ++iter; + + ASSERT_EQ(uint32_t(7), iter.index()); + ASSERT_TRUE(NULL == *iter); + ASSERT_NE(v.endEntries(), iter); + iter++; - ASSERT_EQ(v.endEntries(), iter); + ASSERT_EQ(uint32_t(8), iter.index()); + ASSERT_TRUE(NULL != *iter); + ASSERT_EQ(iter->is_compact(), compact_entry); + ASSERT_EQ(uint32_t(8), iter->key()); + ASSERT_EQ(uint32_t(0x87654321), iter->value().data); + ASSERT_EQ(Res_value::TYPE_STRING, iter->value().dataType); - free(data); + ++iter; + + ASSERT_EQ(v.endEntries(), iter); } } diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp index 8af4b7e8f4c8..4fecf4de0312 100644 --- a/libs/protoutil/Android.bp +++ b/libs/protoutil/Android.bp @@ -59,7 +59,6 @@ cc_library { apex_available: [ "//apex_available:platform", "com.android.os.statsd", - "test_com.android.os.statsd", "com.android.uprobestats", ], } diff --git a/location/api/system-current.txt b/location/api/system-current.txt index ba4224137cd4..eb19ba84ee62 100644 --- a/location/api/system-current.txt +++ b/location/api/system-current.txt @@ -1,6 +1,29 @@ // Signature format: 2.0 package android.location { + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class AuxiliaryInformation implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.location.GnssSignalType> getAvailableSignalTypes(); + method @IntRange(from=0xfffffff9, to=6) public int getFrequencyChannelNumber(); + method public int getSatType(); + method @IntRange(from=1) public int getSvid(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int BDS_B1C_ORBIT_TYPE_GEO = 1; // 0x1 + field public static final int BDS_B1C_ORBIT_TYPE_IGSO = 2; // 0x2 + field public static final int BDS_B1C_ORBIT_TYPE_MEO = 3; // 0x3 + field public static final int BDS_B1C_ORBIT_TYPE_UNDEFINED = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator<android.location.AuxiliaryInformation> CREATOR; + } + + public static final class AuxiliaryInformation.Builder { + ctor public AuxiliaryInformation.Builder(); + method @NonNull public android.location.AuxiliaryInformation build(); + method @NonNull public android.location.AuxiliaryInformation.Builder setAvailableSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>); + method @NonNull public android.location.AuxiliaryInformation.Builder setFrequencyChannelNumber(@IntRange(from=0xfffffff9, to=6) int); + method @NonNull public android.location.AuxiliaryInformation.Builder setSatType(int); + method @NonNull public android.location.AuxiliaryInformation.Builder setSvid(@IntRange(from=1) int); + } + public abstract class BatchedLocationCallback { ctor public BatchedLocationCallback(); method public void onLocationBatch(java.util.List<android.location.Location>); @@ -9,6 +32,7 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class BeidouAssistance implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation(); method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); @@ -24,22 +48,23 @@ package android.location { ctor public BeidouAssistance.Builder(); method @NonNull public android.location.BeidouAssistance build(); method @NonNull public android.location.BeidouAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.BeidouAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation); method @NonNull public android.location.BeidouAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); method @NonNull public android.location.BeidouAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); - method @NonNull public android.location.BeidouAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); - method @NonNull public android.location.BeidouAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); - method @NonNull public android.location.BeidouAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.BeidouSatelliteEphemeris>); - method @NonNull public android.location.BeidouAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.BeidouAssistance.Builder setRealTimeIntegrityModels(@NonNull java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.BeidouAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.BeidouAssistance.Builder setSatelliteEphemeris(@NonNull java.util.List<android.location.BeidouSatelliteEphemeris>); + method @NonNull public android.location.BeidouAssistance.Builder setTimeModels(@NonNull java.util.List<android.location.TimeModel>); method @NonNull public android.location.BeidouAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); } @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class BeidouSatelliteEphemeris implements android.os.Parcelable { method public int describeContents(); - method @IntRange(from=1, to=63) public int getPrn(); method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel getSatelliteClockModel(); method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime getSatelliteEphemerisTime(); method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth getSatelliteHealth(); method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method @IntRange(from=1, to=63) public int getSvid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris> CREATOR; } @@ -104,11 +129,11 @@ package android.location { public static final class BeidouSatelliteEphemeris.Builder { ctor public BeidouSatelliteEphemeris.Builder(); method @NonNull public android.location.BeidouSatelliteEphemeris build(); - method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setPrn(int); method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel); method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime); method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth); method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSvid(int); } public final class CorrelationVector implements android.os.Parcelable { @@ -151,6 +176,7 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GalileoAssistance implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation(); method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); @@ -166,12 +192,13 @@ package android.location { ctor public GalileoAssistance.Builder(); method @NonNull public android.location.GalileoAssistance build(); method @NonNull public android.location.GalileoAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.GalileoAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation); method @NonNull public android.location.GalileoAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); method @NonNull public android.location.GalileoAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); - method @NonNull public android.location.GalileoAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); - method @NonNull public android.location.GalileoAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); - method @NonNull public android.location.GalileoAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GalileoSatelliteEphemeris>); - method @NonNull public android.location.GalileoAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GalileoAssistance.Builder setRealTimeIntegrityModels(@NonNull java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.GalileoAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GalileoAssistance.Builder setSatelliteEphemeris(@NonNull java.util.List<android.location.GalileoSatelliteEphemeris>); + method @NonNull public android.location.GalileoAssistance.Builder setTimeModels(@NonNull java.util.List<android.location.TimeModel>); method @NonNull public android.location.GalileoAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); } @@ -195,10 +222,10 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GalileoSatelliteEphemeris implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel> getSatelliteClockModels(); - method @IntRange(from=1, to=36) public int getSatelliteCodeNumber(); method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth getSatelliteHealth(); method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method @IntRange(from=1, to=36) public int getSvid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoSatelliteEphemeris> CREATOR; } @@ -207,10 +234,10 @@ package android.location { ctor public GalileoSatelliteEphemeris.Builder(); method @NonNull public android.location.GalileoSatelliteEphemeris build(); method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteClockModels(@NonNull java.util.List<android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel>); - method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteCodeNumber(@IntRange(from=1, to=36) int); method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GalileoSatelliteEphemeris.GalileoSvHealth); method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSvid(@IntRange(from=1, to=36) int); } public static final class GalileoSatelliteEphemeris.GalileoSatelliteClockModel implements android.os.Parcelable { @@ -243,25 +270,31 @@ package android.location { public static final class GalileoSatelliteEphemeris.GalileoSvHealth implements android.os.Parcelable { method public int describeContents(); - method @IntRange(from=0, to=1) public int getDataValidityStatusE1b(); - method @IntRange(from=0, to=1) public int getDataValidityStatusE5a(); - method @IntRange(from=0, to=1) public int getDataValidityStatusE5b(); - method @IntRange(from=0, to=3) public int getSignalHealthStatusE1b(); - method @IntRange(from=0, to=3) public int getSignalHealthStatusE5a(); - method @IntRange(from=0, to=3) public int getSignalHealthStatusE5b(); + method public int getDataValidityStatusE1b(); + method public int getDataValidityStatusE5a(); + method public int getDataValidityStatusE5b(); + method public int getSignalHealthStatusE1b(); + method public int getSignalHealthStatusE5a(); + method public int getSignalHealthStatusE5b(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoSatelliteEphemeris.GalileoSvHealth> CREATOR; + field public static final int DATA_STATUS_DATA_VALID = 0; // 0x0 + field public static final int DATA_STATUS_WORKING_WITHOUT_GUARANTEE = 1; // 0x1 + field public static final int HEALTH_STATUS_EXTENDED_OPERATION_MODE = 2; // 0x2 + field public static final int HEALTH_STATUS_IN_TEST = 3; // 0x3 + field public static final int HEALTH_STATUS_OK = 0; // 0x0 + field public static final int HEALTH_STATUS_OUT_OF_SERVICE = 1; // 0x1 } public static final class GalileoSatelliteEphemeris.GalileoSvHealth.Builder { ctor public GalileoSatelliteEphemeris.GalileoSvHealth.Builder(); method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth build(); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE1b(@IntRange(from=0, to=1) int); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5a(@IntRange(from=0, to=1) int); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5b(@IntRange(from=0, to=1) int); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE1b(@IntRange(from=0, to=3) int); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5a(@IntRange(from=0, to=3) int); - method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5b(@IntRange(from=0, to=3) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE1b(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5a(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5b(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE1b(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5a(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5b(int); } @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GlonassAlmanac implements android.os.Parcelable { @@ -275,17 +308,19 @@ package android.location { public static final class GlonassAlmanac.GlonassSatelliteAlmanac implements android.os.Parcelable { method public int describeContents(); + method @IntRange(from=1, to=1461) public int getCalendarDayNumber(); method @FloatRange(from=-0.067F, to=0.067f) public double getDeltaI(); method @FloatRange(from=-3600.0F, to=3600.0f) public double getDeltaT(); method @FloatRange(from=-0.004F, to=0.004f) public double getDeltaTDot(); method @FloatRange(from=0.0f, to=0.03f) public double getEccentricity(); - method @IntRange(from=0, to=31) public int getFreqChannel(); + method @IntRange(from=0, to=31) public int getFrequencyChannelNumber(); + method public int getHealthState(); method @FloatRange(from=-1.0F, to=1.0f) public double getLambda(); method @FloatRange(from=-1.0F, to=1.0f) public double getOmega(); method @IntRange(from=1, to=25) public int getSlotNumber(); - method @IntRange(from=0, to=1) public int getSvHealth(); method @FloatRange(from=0.0f, to=44100.0f) public double getTLambda(); method @FloatRange(from=-0.0019F, to=0.0019f) public double getTau(); + method public boolean isGlonassM(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassAlmanac.GlonassSatelliteAlmanac> CREATOR; } @@ -293,15 +328,17 @@ package android.location { public static final class GlonassAlmanac.GlonassSatelliteAlmanac.Builder { ctor public GlonassAlmanac.GlonassSatelliteAlmanac.Builder(); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac build(); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setCalendarDayNumber(@IntRange(from=1, to=1461) int); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaI(@FloatRange(from=-0.067F, to=0.067f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaT(@FloatRange(from=-3600.0F, to=3600.0f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaTDot(@FloatRange(from=-0.004F, to=0.004f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setEccentricity(@FloatRange(from=0.0f, to=0.03f) double); - method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setFreqChannel(@IntRange(from=0, to=31) int); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setFrequencyChannelNumber(@IntRange(from=0, to=31) int); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setGlonassM(boolean); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setHealthState(int); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setLambda(@FloatRange(from=-1.0F, to=1.0f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setOmega(@FloatRange(from=-1.0F, to=1.0f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setSlotNumber(@IntRange(from=1, to=25) int); - method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setSvHealth(@IntRange(from=0, to=1) int); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setTLambda(@FloatRange(from=0.0f, to=44100.0f) double); method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setTau(@FloatRange(from=-0.0019F, to=0.0019f) double); } @@ -309,6 +346,7 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GlonassAssistance implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.GlonassAlmanac getAlmanac(); + method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation(); method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); method @NonNull public java.util.List<android.location.GlonassSatelliteEphemeris> getSatelliteEphemeris(); method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); @@ -321,9 +359,10 @@ package android.location { ctor public GlonassAssistance.Builder(); method @NonNull public android.location.GlonassAssistance build(); method @NonNull public android.location.GlonassAssistance.Builder setAlmanac(@Nullable android.location.GlonassAlmanac); - method @NonNull public android.location.GlonassAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); - method @NonNull public android.location.GlonassAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GlonassSatelliteEphemeris>); - method @NonNull public android.location.GlonassAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GlonassAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation); + method @NonNull public android.location.GlonassAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GlonassAssistance.Builder setSatelliteEphemeris(@NonNull java.util.List<android.location.GlonassSatelliteEphemeris>); + method @NonNull public android.location.GlonassAssistance.Builder setTimeModels(@NonNull java.util.List<android.location.TimeModel>); method @NonNull public android.location.GlonassAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); } @@ -331,12 +370,17 @@ package android.location { method public int describeContents(); method @IntRange(from=0, to=31) public int getAgeInDays(); method @FloatRange(from=0.0f) public double getFrameTimeSeconds(); - method @IntRange(from=0, to=1) public int getHealthState(); + method public int getHealthState(); method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel getSatelliteClockModel(); method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel getSatelliteOrbitModel(); method @IntRange(from=1, to=25) public int getSlotNumber(); + method @IntRange(from=0, to=60) public int getUpdateIntervalMinutes(); + method public boolean isGlonassM(); + method public boolean isUpdateIntervalOdd(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassSatelliteEphemeris> CREATOR; + field public static final int HEALTH_STATUS_HEALTHY = 0; // 0x0 + field public static final int HEALTH_STATUS_UNHEALTHY = 1; // 0x1 } public static final class GlonassSatelliteEphemeris.Builder { @@ -344,18 +388,23 @@ package android.location { method @NonNull public android.location.GlonassSatelliteEphemeris build(); method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setAgeInDays(@IntRange(from=0, to=31) int); method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setFrameTimeSeconds(@FloatRange(from=0.0f) double); - method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setHealthState(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setGlonassM(boolean); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setHealthState(int); method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel); method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel); method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSlotNumber(@IntRange(from=1, to=25) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setUpdateIntervalMinutes(@IntRange(from=0, to=60) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setUpdateIntervalOdd(boolean); } public static final class GlonassSatelliteEphemeris.GlonassSatelliteClockModel implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-0.002F, to=0.002f) public double getClockBias(); method @FloatRange(from=-9.32E-10F, to=9.32E-10f) public double getFrequencyBias(); - method @IntRange(from=0xfffffff9, to=6) public int getFrequencyNumber(); + method @IntRange(from=0xfffffff9, to=6) public int getFrequencyChannelNumber(); + method @FloatRange(from=-1.4E-8F, to=1.4E-8f) public double getGroupDelayDiffSeconds(); method @IntRange(from=0) public long getTimeOfClockSeconds(); + method public boolean isGroupDelayDiffSecondsAvailable(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel> CREATOR; } @@ -365,7 +414,9 @@ package android.location { method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel build(); method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setClockBias(@FloatRange(from=-0.002F, to=0.002f) double); method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setFrequencyBias(@FloatRange(from=-9.32E-10F, to=9.32E-10f) double); - method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setFrequencyNumber(@IntRange(from=0xfffffff9, to=6) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setFrequencyChannelNumber(@IntRange(from=0xfffffff9, to=6) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setGroupDelayDiffSeconds(@FloatRange(from=-1.4E-8F, to=1.4E-8f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setGroupDelayDiffSecondsAvailable(boolean); method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setTimeOfClockSeconds(@IntRange(from=0) long); } @@ -401,10 +452,11 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GnssAlmanac implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.location.GnssAlmanac.GnssSatelliteAlmanac> getGnssSatelliteAlmanacs(); - method @IntRange(from=0) public int getIod(); + method @IntRange(from=0) public int getIoda(); method @IntRange(from=0) public long getIssueDateMillis(); method @IntRange(from=0, to=604800) public int getToaSeconds(); method @IntRange(from=0) public int getWeekNumber(); + method public boolean isCompleteAlmanacProvided(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAlmanac> CREATOR; } @@ -412,8 +464,9 @@ package android.location { public static final class GnssAlmanac.Builder { ctor public GnssAlmanac.Builder(); method @NonNull public android.location.GnssAlmanac build(); + method @NonNull public android.location.GnssAlmanac.Builder setCompleteAlmanacProvided(boolean); method @NonNull public android.location.GnssAlmanac.Builder setGnssSatelliteAlmanacs(@NonNull java.util.List<android.location.GnssAlmanac.GnssSatelliteAlmanac>); - method @NonNull public android.location.GnssAlmanac.Builder setIod(@IntRange(from=0) int); + method @NonNull public android.location.GnssAlmanac.Builder setIoda(@IntRange(from=0) int); method @NonNull public android.location.GnssAlmanac.Builder setIssueDateMillis(@IntRange(from=0) long); method @NonNull public android.location.GnssAlmanac.Builder setToaSeconds(@IntRange(from=0, to=604800) int); method @NonNull public android.location.GnssAlmanac.Builder setWeekNumber(@IntRange(from=0) int); @@ -664,6 +717,7 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GpsAssistance implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation(); method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); @@ -679,12 +733,13 @@ package android.location { ctor public GpsAssistance.Builder(); method @NonNull public android.location.GpsAssistance build(); method @NonNull public android.location.GpsAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.GpsAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation); method @NonNull public android.location.GpsAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); method @NonNull public android.location.GpsAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); - method @NonNull public android.location.GpsAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); - method @NonNull public android.location.GpsAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); - method @NonNull public android.location.GpsAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GpsSatelliteEphemeris>); - method @NonNull public android.location.GpsAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GpsAssistance.Builder setRealTimeIntegrityModels(@NonNull java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.GpsAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GpsAssistance.Builder setSatelliteEphemeris(@NonNull java.util.List<android.location.GpsSatelliteEphemeris>); + method @NonNull public android.location.GpsAssistance.Builder setTimeModels(@NonNull java.util.List<android.location.TimeModel>); method @NonNull public android.location.GpsAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); } @@ -916,11 +971,11 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GpsSatelliteEphemeris implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params getGpsL2Params(); - method @IntRange(from=1, to=32) public int getPrn(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel getSatelliteClockModel(); method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth getSatelliteHealth(); method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method @IntRange(from=1, to=32) public int getSvid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsSatelliteEphemeris> CREATOR; } @@ -929,11 +984,11 @@ package android.location { ctor public GpsSatelliteEphemeris.Builder(); method @NonNull public android.location.GpsSatelliteEphemeris build(); method @NonNull public android.location.GpsSatelliteEphemeris.Builder setGpsL2Params(@NonNull android.location.GpsSatelliteEphemeris.GpsL2Params); - method @NonNull public android.location.GpsSatelliteEphemeris.Builder setPrn(@IntRange(from=1, to=32) int); method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel); method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteHealth); method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSvid(@IntRange(from=1, to=32) int); } public static final class GpsSatelliteEphemeris.GpsL2Params implements android.os.Parcelable { @@ -1198,6 +1253,7 @@ package android.location { @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class QzssAssistance implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.AuxiliaryInformation getAuxiliaryInformation(); method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); @@ -1213,23 +1269,24 @@ package android.location { ctor public QzssAssistance.Builder(); method @NonNull public android.location.QzssAssistance build(); method @NonNull public android.location.QzssAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.QzssAssistance.Builder setAuxiliaryInformation(@Nullable android.location.AuxiliaryInformation); method @NonNull public android.location.QzssAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); method @NonNull public android.location.QzssAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); - method @NonNull public android.location.QzssAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); - method @NonNull public android.location.QzssAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); - method @NonNull public android.location.QzssAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.QzssSatelliteEphemeris>); - method @NonNull public android.location.QzssAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.QzssAssistance.Builder setRealTimeIntegrityModels(@NonNull java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.QzssAssistance.Builder setSatelliteCorrections(@NonNull java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.QzssAssistance.Builder setSatelliteEphemeris(@NonNull java.util.List<android.location.QzssSatelliteEphemeris>); + method @NonNull public android.location.QzssAssistance.Builder setTimeModels(@NonNull java.util.List<android.location.TimeModel>); method @NonNull public android.location.QzssAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); } @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class QzssSatelliteEphemeris implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params getGpsL2Params(); - method @IntRange(from=183, to=206) public int getPrn(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel getSatelliteClockModel(); method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth getSatelliteHealth(); method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method @IntRange(from=183, to=206) public int getSvid(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.QzssSatelliteEphemeris> CREATOR; } @@ -1238,22 +1295,22 @@ package android.location { ctor public QzssSatelliteEphemeris.Builder(); method @NonNull public android.location.QzssSatelliteEphemeris build(); method @NonNull public android.location.QzssSatelliteEphemeris.Builder setGpsL2Params(@NonNull android.location.GpsSatelliteEphemeris.GpsL2Params); - method @NonNull public android.location.QzssSatelliteEphemeris.Builder setPrn(@IntRange(from=183, to=206) int); method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel); method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteHealth); method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSvid(@IntRange(from=183, to=206) int); } @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class RealTimeIntegrityModel implements android.os.Parcelable { method public int describeContents(); method @NonNull public String getAdvisoryNumber(); method @NonNull public String getAdvisoryType(); + method @NonNull public java.util.List<android.location.GnssSignalType> getBadSignalTypes(); + method @IntRange(from=1, to=206) public int getBadSvid(); method @IntRange(from=0) public long getEndDateSeconds(); method @IntRange(from=0) public long getPublishDateSeconds(); method @IntRange(from=0) public long getStartDateSeconds(); - method @IntRange(from=1, to=206) public int getSvid(); - method public boolean isUsable(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.RealTimeIntegrityModel> CREATOR; } @@ -1263,11 +1320,11 @@ package android.location { method @NonNull public android.location.RealTimeIntegrityModel build(); method @NonNull public android.location.RealTimeIntegrityModel.Builder setAdvisoryNumber(@NonNull String); method @NonNull public android.location.RealTimeIntegrityModel.Builder setAdvisoryType(@NonNull String); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setBadSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setBadSvid(@IntRange(from=1, to=206) int); method @NonNull public android.location.RealTimeIntegrityModel.Builder setEndDateSeconds(@IntRange(from=0) long); method @NonNull public android.location.RealTimeIntegrityModel.Builder setPublishDateSeconds(@IntRange(from=0) long); method @NonNull public android.location.RealTimeIntegrityModel.Builder setStartDateSeconds(@IntRange(from=0) long); - method @NonNull public android.location.RealTimeIntegrityModel.Builder setSvid(@IntRange(from=1, to=206) int); - method @NonNull public android.location.RealTimeIntegrityModel.Builder setUsable(boolean); } @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class SatelliteEphemerisTime implements android.os.Parcelable { @@ -1435,6 +1492,13 @@ package android.location.provider { field public static final String ACTION_GEOCODE_PROVIDER = "com.android.location.service.GeocodeProvider"; } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public abstract class GnssAssistanceProviderBase { + ctor public GnssAssistanceProviderBase(@NonNull android.content.Context, @NonNull String); + method @NonNull public final android.os.IBinder getBinder(); + method public abstract void onRequest(@NonNull android.os.OutcomeReceiver<android.location.GnssAssistance,java.lang.Throwable>); + field public static final String ACTION_GNSS_ASSISTANCE_PROVIDER = "android.location.provider.action.GNSS_ASSISTANCE_PROVIDER"; + } + public abstract class LocationProviderBase { ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties); method @Nullable public final android.os.IBinder getBinder(); diff --git a/location/java/android/location/AuxiliaryInformation.java b/location/java/android/location/AuxiliaryInformation.java new file mode 100644 index 000000000000..601c87e69b70 --- /dev/null +++ b/location/java/android/location/AuxiliaryInformation.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains parameters to provide additional assistance information dependent on the GNSS + * constellation. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class AuxiliaryInformation implements Parcelable { + + /** + * BDS B1C Satellite orbit type. + * + * <p>This is defined in BDS-SIS-ICD-B1I-3.0, section 3.1. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + BDS_B1C_ORBIT_TYPE_UNDEFINED, + BDS_B1C_ORBIT_TYPE_GEO, + BDS_B1C_ORBIT_TYPE_IGSO, + BDS_B1C_ORBIT_TYPE_MEO + }) + public @interface BeidouB1CSatelliteOrbitType {} + + /** + * The following enumerations must be in sync with the values declared in + * AuxiliaryInformation.aidl. + */ + + /** The orbit type is undefined. */ + public static final int BDS_B1C_ORBIT_TYPE_UNDEFINED = 0; + + /** The orbit type is GEO. */ + public static final int BDS_B1C_ORBIT_TYPE_GEO = 1; + + /** The orbit type is IGSO. */ + public static final int BDS_B1C_ORBIT_TYPE_IGSO = 2; + + /** The orbit type is MEO. */ + public static final int BDS_B1C_ORBIT_TYPE_MEO = 3; + + /** + * Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle (SV), or OSN + * number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values must be in the range + * of: + * + * <p>- GPS: 1-32 + * + * <p>- GLONASS: 1-25 + * + * <p>- QZSS: 183-206 + * + * <p>- Galileo: 1-36 + * + * <p>- Beidou: 1-63 + */ + private final int mSvid; + + /** The list of available signal types for the satellite. */ + @NonNull private final List<GnssSignalType> mAvailableSignalTypes; + + /** + * Glonass carrier frequency number of the satellite. This is required for Glonass. + * + * <p>This is defined in Glonass ICD v5.1 section 3.3.1.1. + */ + private final int mFrequencyChannelNumber; + + /** BDS B1C satellite orbit type. This is required for Beidou. */ + private final @BeidouB1CSatelliteOrbitType int mSatType; + + private AuxiliaryInformation(Builder builder) { + // Allow Svid beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); + Preconditions.checkNotNull( + builder.mAvailableSignalTypes, "AvailableSignalTypes cannot be null"); + Preconditions.checkArgument(builder.mAvailableSignalTypes.size() > 0); + Preconditions.checkArgumentInRange( + builder.mFrequencyChannelNumber, -7, 6, "FrequencyChannelNumber"); + Preconditions.checkArgumentInRange( + builder.mSatType, BDS_B1C_ORBIT_TYPE_UNDEFINED, BDS_B1C_ORBIT_TYPE_MEO, "SatType"); + mSvid = builder.mSvid; + mAvailableSignalTypes = + Collections.unmodifiableList(new ArrayList<>(builder.mAvailableSignalTypes)); + mFrequencyChannelNumber = builder.mFrequencyChannelNumber; + mSatType = builder.mSatType; + } + + /** + * Returns the Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle + * (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values must be in the range + * of: + * + * <p>- GPS: 1-32 + * + * <p>- GLONASS: 1-25 + * + * <p>- QZSS: 183-206 + * + * <p>- Galileo: 1-36 + * + * <p>- Beidou: 1-63 + */ + @IntRange(from = 1) + public int getSvid() { + return mSvid; + } + + /** Returns the list of available signal types for the satellite. */ + @NonNull + public List<GnssSignalType> getAvailableSignalTypes() { + return mAvailableSignalTypes; + } + + /** Returns the Glonass carrier frequency number of the satellite. */ + @IntRange(from = -7, to = 6) + public int getFrequencyChannelNumber() { + return mFrequencyChannelNumber; + } + + /** Returns the BDS B1C satellite orbit type. */ + @BeidouB1CSatelliteOrbitType + public int getSatType() { + return mSatType; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSvid); + dest.writeTypedList(mAvailableSignalTypes); + dest.writeInt(mFrequencyChannelNumber); + dest.writeInt(mSatType); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("AuxiliaryInformation["); + builder.append("svid = ").append(mSvid); + builder.append(", availableSignalTypes = ").append(mAvailableSignalTypes); + builder.append(", frequencyChannelNumber = ").append(mFrequencyChannelNumber); + builder.append(", satType = ").append(mSatType); + builder.append("]"); + return builder.toString(); + } + + public static final @NonNull Parcelable.Creator<AuxiliaryInformation> CREATOR = + new Parcelable.Creator<AuxiliaryInformation>() { + @Override + public AuxiliaryInformation createFromParcel(@NonNull Parcel in) { + return new AuxiliaryInformation.Builder() + .setSvid(in.readInt()) + .setAvailableSignalTypes( + in.createTypedArrayList(GnssSignalType.CREATOR)) + .setFrequencyChannelNumber(in.readInt()) + .setSatType(in.readInt()) + .build(); + } + + @Override + public AuxiliaryInformation[] newArray(int size) { + return new AuxiliaryInformation[size]; + } + }; + + /** A builder class for {@link AuxiliaryInformation}. */ + public static final class Builder { + private int mSvid; + private List<GnssSignalType> mAvailableSignalTypes; + private int mFrequencyChannelNumber; + private @BeidouB1CSatelliteOrbitType int mSatType; + + /** + * Sets the Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle + * (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values must be in the + * range of: + * + * <p>- GPS: 1-32 + * + * <p>- GLONASS: 1-25 + * + * <p>- QZSS: 183-206 + * + * <p>- Galileo: 1-36 + * + * <p>- Beidou: 1-63 + */ + @NonNull + public Builder setSvid(@IntRange(from = 1) int svid) { + mSvid = svid; + return this; + } + + /** + * Sets the list of available signal types for the satellite. + * + * <p>The list must be set and cannot be an empty list. + */ + @NonNull + public Builder setAvailableSignalTypes(@NonNull List<GnssSignalType> availableSignalTypes) { + mAvailableSignalTypes = availableSignalTypes; + return this; + } + + /** Sets the Glonass carrier frequency number of the satellite. */ + @NonNull + public Builder setFrequencyChannelNumber( + @IntRange(from = -7, to = 6) int frequencyChannelNumber) { + mFrequencyChannelNumber = frequencyChannelNumber; + return this; + } + + /** Sets the BDS B1C satellite orbit type. */ + @NonNull + public Builder setSatType(@BeidouB1CSatelliteOrbitType int satType) { + mSatType = satType; + return this; + } + + /** Builds a {@link AuxiliaryInformation} instance as specified by this builder. */ + @NonNull + public AuxiliaryInformation build() { + return new AuxiliaryInformation(this); + } + } +} diff --git a/location/java/android/location/BeidouAssistance.java b/location/java/android/location/BeidouAssistance.java index f55249e605a0..e35493ed1007 100644 --- a/location/java/android/location/BeidouAssistance.java +++ b/location/java/android/location/BeidouAssistance.java @@ -19,7 +19,6 @@ package android.location; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.location.GnssAssistance.GnssSatelliteCorrections; import android.location.flags.Flags; @@ -51,6 +50,9 @@ public final class BeidouAssistance implements Parcelable { /** The leap seconds model. */ @Nullable private final LeapSecondsModel mLeapSecondsModel; + /** The auxiliary information. */ + @Nullable private final AuxiliaryInformation mAuxiliaryInformation; + /** The list of time models. */ @NonNull private final List<TimeModel> mTimeModels; @@ -68,6 +70,7 @@ public final class BeidouAssistance implements Parcelable { mIonosphericModel = builder.mIonosphericModel; mUtcModel = builder.mUtcModel; mLeapSecondsModel = builder.mLeapSecondsModel; + mAuxiliaryInformation = builder.mAuxiliaryInformation; if (builder.mTimeModels != null) { mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); } else { @@ -117,6 +120,12 @@ public final class BeidouAssistance implements Parcelable { return mLeapSecondsModel; } + /** Returns the auxiliary information. */ + @Nullable + public AuxiliaryInformation getAuxiliaryInformation() { + return mAuxiliaryInformation; + } + /** Returns the list of time models. */ @NonNull public List<TimeModel> getTimeModels() { @@ -154,6 +163,7 @@ public final class BeidouAssistance implements Parcelable { builder.append(", ionosphericModel = ").append(mIonosphericModel); builder.append(", utcModel = ").append(mUtcModel); builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", auxiliaryInformation = ").append(mAuxiliaryInformation); builder.append(", timeModels = ").append(mTimeModels); builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); @@ -168,6 +178,7 @@ public final class BeidouAssistance implements Parcelable { dest.writeTypedObject(mIonosphericModel, flags); dest.writeTypedObject(mUtcModel, flags); dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedObject(mAuxiliaryInformation, flags); dest.writeTypedList(mTimeModels); dest.writeTypedList(mSatelliteEphemeris); dest.writeTypedList(mRealTimeIntegrityModels); @@ -184,6 +195,8 @@ public final class BeidouAssistance implements Parcelable { in.readTypedObject(KlobucharIonosphericModel.CREATOR)) .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setAuxiliaryInformation( + in.readTypedObject(AuxiliaryInformation.CREATOR)) .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) .setSatelliteEphemeris( in.createTypedArrayList(BeidouSatelliteEphemeris.CREATOR)) @@ -206,6 +219,7 @@ public final class BeidouAssistance implements Parcelable { private KlobucharIonosphericModel mIonosphericModel; private UtcModel mUtcModel; private LeapSecondsModel mLeapSecondsModel; + private AuxiliaryInformation mAuxiliaryInformation; private List<TimeModel> mTimeModels; private List<BeidouSatelliteEphemeris> mSatelliteEphemeris; private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; @@ -239,10 +253,17 @@ public final class BeidouAssistance implements Parcelable { return this; } + /** Sets the auxiliary information. */ + @NonNull + public Builder setAuxiliaryInformation( + @Nullable AuxiliaryInformation auxiliaryInformation) { + mAuxiliaryInformation = auxiliaryInformation; + return this; + } + /** Sets the list of time models. */ @NonNull - public Builder setTimeModels( - @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + public Builder setTimeModels(@NonNull List<TimeModel> timeModels) { mTimeModels = timeModels; return this; } @@ -250,8 +271,7 @@ public final class BeidouAssistance implements Parcelable { /** Sets the list of Beidou ephemeris. */ @NonNull public Builder setSatelliteEphemeris( - @Nullable @SuppressLint("NullableCollection") - List<BeidouSatelliteEphemeris> satelliteEphemeris) { + @NonNull List<BeidouSatelliteEphemeris> satelliteEphemeris) { mSatelliteEphemeris = satelliteEphemeris; return this; } @@ -259,8 +279,7 @@ public final class BeidouAssistance implements Parcelable { /** Sets the list of real time integrity models. */ @NonNull public Builder setRealTimeIntegrityModels( - @Nullable @SuppressLint("NullableCollection") - List<RealTimeIntegrityModel> realTimeIntegrityModels) { + @NonNull List<RealTimeIntegrityModel> realTimeIntegrityModels) { mRealTimeIntegrityModels = realTimeIntegrityModels; return this; } @@ -268,8 +287,7 @@ public final class BeidouAssistance implements Parcelable { /** Sets the list of Beidou satellite corrections. */ @NonNull public Builder setSatelliteCorrections( - @Nullable @SuppressLint("NullableCollection") - List<GnssSatelliteCorrections> satelliteCorrections) { + @NonNull List<GnssSatelliteCorrections> satelliteCorrections) { mSatelliteCorrections = satelliteCorrections; return this; } diff --git a/location/java/android/location/BeidouSatelliteEphemeris.java b/location/java/android/location/BeidouSatelliteEphemeris.java index 6bd91e3318c3..3382c20964d9 100644 --- a/location/java/android/location/BeidouSatelliteEphemeris.java +++ b/location/java/android/location/BeidouSatelliteEphemeris.java @@ -35,8 +35,8 @@ import com.android.internal.util.Preconditions; @FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) @SystemApi public final class BeidouSatelliteEphemeris implements Parcelable { - /** The PRN number of the Beidou satellite. */ - private final int mPrn; + /** The PRN or satellite ID number for the Beidou satellite. */ + private final int mSvid; /** Satellite clock model. */ private final BeidouSatelliteClockModel mSatelliteClockModel; @@ -51,8 +51,8 @@ public final class BeidouSatelliteEphemeris implements Parcelable { private final BeidouSatelliteEphemerisTime mSatelliteEphemerisTime; private BeidouSatelliteEphemeris(Builder builder) { - // Allow PRN beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mPrn >= 1); + // Allow Svid beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); Preconditions.checkNotNull(builder.mSatelliteClockModel, "SatelliteClockModel cannot be null"); Preconditions.checkNotNull(builder.mSatelliteOrbitModel, @@ -61,17 +61,17 @@ public final class BeidouSatelliteEphemeris implements Parcelable { "SatelliteHealth cannot be null"); Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, "SatelliteEphemerisTime cannot be null"); - mPrn = builder.mPrn; + mSvid = builder.mSvid; mSatelliteClockModel = builder.mSatelliteClockModel; mSatelliteOrbitModel = builder.mSatelliteOrbitModel; mSatelliteHealth = builder.mSatelliteHealth; mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; } - /** Returns the PRN of the satellite. */ + /** Returns the PRN or satellite ID number for the Beidou satellite. */ @IntRange(from = 1, to = 63) - public int getPrn() { - return mPrn; + public int getSvid() { + return mSvid; } /** Returns the satellite clock model. */ @@ -105,7 +105,7 @@ public final class BeidouSatelliteEphemeris implements Parcelable { public BeidouSatelliteEphemeris createFromParcel(Parcel in) { final BeidouSatelliteEphemeris.Builder beidouSatelliteEphemeris = new Builder() - .setPrn(in.readInt()) + .setSvid(in.readInt()) .setSatelliteClockModel( in.readTypedObject(BeidouSatelliteClockModel.CREATOR)) .setSatelliteOrbitModel( @@ -131,7 +131,7 @@ public final class BeidouSatelliteEphemeris implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mPrn); + parcel.writeInt(mSvid); parcel.writeTypedObject(mSatelliteClockModel, flags); parcel.writeTypedObject(mSatelliteOrbitModel, flags); parcel.writeTypedObject(mSatelliteHealth, flags); @@ -142,7 +142,7 @@ public final class BeidouSatelliteEphemeris implements Parcelable { @NonNull public String toString() { StringBuilder builder = new StringBuilder("BeidouSatelliteEphemeris["); - builder.append("prn = ").append(mPrn); + builder.append("svid = ").append(mSvid); builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); builder.append(", satelliteHealth = ").append(mSatelliteHealth); @@ -153,16 +153,16 @@ public final class BeidouSatelliteEphemeris implements Parcelable { /** Builder for {@link BeidouSatelliteEphemeris} */ public static final class Builder { - private int mPrn; + private int mSvid; private BeidouSatelliteClockModel mSatelliteClockModel; private KeplerianOrbitModel mSatelliteOrbitModel; private BeidouSatelliteHealth mSatelliteHealth; private BeidouSatelliteEphemerisTime mSatelliteEphemerisTime; - /** Sets the PRN of the satellite. */ + /** Sets the PRN or satellite ID number for the Beidou satellite. */ @NonNull - public Builder setPrn(int prn) { - mPrn = prn; + public Builder setSvid(int svid) { + mSvid = svid; return this; } diff --git a/location/java/android/location/GalileoAssistance.java b/location/java/android/location/GalileoAssistance.java index 07c5bab856db..8a09e6634d09 100644 --- a/location/java/android/location/GalileoAssistance.java +++ b/location/java/android/location/GalileoAssistance.java @@ -19,7 +19,6 @@ package android.location; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.location.GnssAssistance.GnssSatelliteCorrections; import android.location.flags.Flags; @@ -51,6 +50,9 @@ public final class GalileoAssistance implements Parcelable { /** The leap seconds model. */ @Nullable private final LeapSecondsModel mLeapSecondsModel; + /** The auxiliary information. */ + @Nullable private final AuxiliaryInformation mAuxiliaryInformation; + /** The list of time models. */ @NonNull private final List<TimeModel> mTimeModels; @@ -68,6 +70,7 @@ public final class GalileoAssistance implements Parcelable { mIonosphericModel = builder.mIonosphericModel; mUtcModel = builder.mUtcModel; mLeapSecondsModel = builder.mLeapSecondsModel; + mAuxiliaryInformation = builder.mAuxiliaryInformation; if (builder.mTimeModels != null) { mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); } else { @@ -117,6 +120,12 @@ public final class GalileoAssistance implements Parcelable { return mLeapSecondsModel; } + /** Returns the auxiliary information. */ + @Nullable + public AuxiliaryInformation getAuxiliaryInformation() { + return mAuxiliaryInformation; + } + /** Returns the list of time models. */ @NonNull public List<TimeModel> getTimeModels() { @@ -152,6 +161,7 @@ public final class GalileoAssistance implements Parcelable { dest.writeTypedObject(mIonosphericModel, flags); dest.writeTypedObject(mUtcModel, flags); dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedObject(mAuxiliaryInformation, flags); dest.writeTypedList(mTimeModels); dest.writeTypedList(mSatelliteEphemeris); dest.writeTypedList(mRealTimeIntegrityModels); @@ -166,6 +176,7 @@ public final class GalileoAssistance implements Parcelable { builder.append(", ionosphericModel = ").append(mIonosphericModel); builder.append(", utcModel = ").append(mUtcModel); builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", auxiliaryInformation = ").append(mAuxiliaryInformation); builder.append(", timeModels = ").append(mTimeModels); builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); @@ -184,6 +195,8 @@ public final class GalileoAssistance implements Parcelable { in.readTypedObject(KlobucharIonosphericModel.CREATOR)) .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setAuxiliaryInformation( + in.readTypedObject(AuxiliaryInformation.CREATOR)) .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) .setSatelliteEphemeris( in.createTypedArrayList(GalileoSatelliteEphemeris.CREATOR)) @@ -206,6 +219,7 @@ public final class GalileoAssistance implements Parcelable { private KlobucharIonosphericModel mIonosphericModel; private UtcModel mUtcModel; private LeapSecondsModel mLeapSecondsModel; + private AuxiliaryInformation mAuxiliaryInformation; private List<TimeModel> mTimeModels; private List<GalileoSatelliteEphemeris> mSatelliteEphemeris; private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; @@ -239,10 +253,17 @@ public final class GalileoAssistance implements Parcelable { return this; } + /** Sets the auxiliary information. */ + @NonNull + public Builder setAuxiliaryInformation( + @Nullable AuxiliaryInformation auxiliaryInformation) { + mAuxiliaryInformation = auxiliaryInformation; + return this; + } + /** Sets the list of time models. */ @NonNull - public Builder setTimeModels( - @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + public Builder setTimeModels(@NonNull List<TimeModel> timeModels) { mTimeModels = timeModels; return this; } @@ -250,8 +271,7 @@ public final class GalileoAssistance implements Parcelable { /** Sets the list of Galileo ephemeris. */ @NonNull public Builder setSatelliteEphemeris( - @Nullable @SuppressLint("NullableCollection") - List<GalileoSatelliteEphemeris> satelliteEphemeris) { + @NonNull List<GalileoSatelliteEphemeris> satelliteEphemeris) { mSatelliteEphemeris = satelliteEphemeris; return this; } @@ -259,8 +279,7 @@ public final class GalileoAssistance implements Parcelable { /** Sets the list of real time integrity models. */ @NonNull public Builder setRealTimeIntegrityModels( - @Nullable @SuppressLint("NullableCollection") - List<RealTimeIntegrityModel> realTimeIntegrityModels) { + @NonNull List<RealTimeIntegrityModel> realTimeIntegrityModels) { mRealTimeIntegrityModels = realTimeIntegrityModels; return this; } @@ -268,8 +287,7 @@ public final class GalileoAssistance implements Parcelable { /** Sets the list of Galileo satellite corrections. */ @NonNull public Builder setSatelliteCorrections( - @Nullable @SuppressLint("NullableCollection") - List<GnssSatelliteCorrections> satelliteCorrections) { + @NonNull List<GnssSatelliteCorrections> satelliteCorrections) { mSatelliteCorrections = satelliteCorrections; return this; } diff --git a/location/java/android/location/GalileoSatelliteEphemeris.java b/location/java/android/location/GalileoSatelliteEphemeris.java index 7dd371176267..08218f4bf83e 100644 --- a/location/java/android/location/GalileoSatelliteEphemeris.java +++ b/location/java/android/location/GalileoSatelliteEphemeris.java @@ -43,8 +43,8 @@ import java.util.List; @SystemApi public final class GalileoSatelliteEphemeris implements Parcelable { - /** Satellite code number. */ - private int mSatelliteCodeNumber; + /** PRN or satellite ID number for the Galileo satellite. */ + private int mSvid; /** Array of satellite clock model. */ @NonNull private final List<GalileoSatelliteClockModel> mSatelliteClockModels; @@ -59,8 +59,8 @@ public final class GalileoSatelliteEphemeris implements Parcelable { @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; private GalileoSatelliteEphemeris(Builder builder) { - // Allow satelliteCodeNumber beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mSatelliteCodeNumber >= 1); + // Allow svid beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); Preconditions.checkNotNull( builder.mSatelliteClockModels, "SatelliteClockModels cannot be null"); Preconditions.checkNotNull( @@ -68,7 +68,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { Preconditions.checkNotNull(builder.mSatelliteHealth, "SatelliteHealth cannot be null"); Preconditions.checkNotNull( builder.mSatelliteEphemerisTime, "SatelliteEphemerisTime cannot be null"); - mSatelliteCodeNumber = builder.mSatelliteCodeNumber; + mSvid = builder.mSvid; final List<GalileoSatelliteClockModel> satelliteClockModels = builder.mSatelliteClockModels; mSatelliteClockModels = Collections.unmodifiableList(new ArrayList<>(satelliteClockModels)); mSatelliteOrbitModel = builder.mSatelliteOrbitModel; @@ -76,10 +76,10 @@ public final class GalileoSatelliteEphemeris implements Parcelable { mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; } - /** Returns the satellite code number. */ + /** Returns the PRN or satellite ID number for the Galileo satellite. */ @IntRange(from = 1, to = 36) - public int getSatelliteCodeNumber() { - return mSatelliteCodeNumber; + public int getSvid() { + return mSvid; } /** Returns the list of satellite clock models. */ @@ -113,7 +113,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { public GalileoSatelliteEphemeris createFromParcel(Parcel in) { final GalileoSatelliteEphemeris.Builder galileoSatelliteEphemeris = new Builder(); - galileoSatelliteEphemeris.setSatelliteCodeNumber(in.readInt()); + galileoSatelliteEphemeris.setSvid(in.readInt()); List<GalileoSatelliteClockModel> satelliteClockModels = new ArrayList<>(); in.readTypedList(satelliteClockModels, GalileoSatelliteClockModel.CREATOR); galileoSatelliteEphemeris.setSatelliteClockModels(satelliteClockModels); @@ -139,7 +139,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mSatelliteCodeNumber); + parcel.writeInt(mSvid); parcel.writeTypedList(mSatelliteClockModels, flags); parcel.writeTypedObject(mSatelliteOrbitModel, flags); parcel.writeTypedObject(mSatelliteHealth, flags); @@ -150,7 +150,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { @NonNull public String toString() { StringBuilder builder = new StringBuilder("GalileoSatelliteEphemeris["); - builder.append("satelliteCodeNumber = ").append(mSatelliteCodeNumber); + builder.append("svid = ").append(mSvid); builder.append(", satelliteClockModels = ").append(mSatelliteClockModels); builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); builder.append(", satelliteHealth = ").append(mSatelliteHealth); @@ -161,17 +161,16 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Builder for {@link GalileoSatelliteEphemeris}. */ public static final class Builder { - private int mSatelliteCodeNumber; + private int mSvid; private List<GalileoSatelliteClockModel> mSatelliteClockModels; private KeplerianOrbitModel mSatelliteOrbitModel; private GalileoSvHealth mSatelliteHealth; private SatelliteEphemerisTime mSatelliteEphemerisTime; - /** Sets the satellite code number. */ + /** Sets the PRN or satellite ID number for the Galileo satellite. */ @NonNull - public Builder setSatelliteCodeNumber( - @IntRange(from = 1, to = 36) int satelliteCodeNumber) { - mSatelliteCodeNumber = satelliteCodeNumber; + public Builder setSvid(@IntRange(from = 1, to = 36) int svid) { + mSvid = svid; return this; } @@ -218,37 +217,107 @@ public final class GalileoSatelliteEphemeris implements Parcelable { * <p>This is defined in Galileo-OS-SIS-ICD 5.1.9.3. */ public static final class GalileoSvHealth implements Parcelable { + + /** + * Galileo data validity status. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({DATA_STATUS_DATA_VALID, DATA_STATUS_WORKING_WITHOUT_GUARANTEE}) + public @interface GalileoDataValidityStatus {} + + /** + * The following enumerations must be in sync with the values declared in + * GalileoHealthDataVaidityType in GalileoSatelliteEphemeris.aidl. + */ + + /** Data validity status is data valid. */ + public static final int DATA_STATUS_DATA_VALID = 0; + + /** Data validity status is working without guarantee. */ + public static final int DATA_STATUS_WORKING_WITHOUT_GUARANTEE = 1; + + /** + * Galileo signal health status. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + HEALTH_STATUS_OK, + HEALTH_STATUS_OUT_OF_SERVICE, + HEALTH_STATUS_EXTENDED_OPERATION_MODE, + HEALTH_STATUS_IN_TEST + }) + public @interface GalileoHealthStatus {} + + /** + * The following enumerations must be in sync with the values declared in + * GalileoHealthStatusType in GalileoSatelliteEphemeris.aidl. + */ + + /** Health status is ok. */ + public static final int HEALTH_STATUS_OK = 0; + + /** Health status is out of service. */ + public static final int HEALTH_STATUS_OUT_OF_SERVICE = 1; + + /** Health status is in extended operation mode. */ + public static final int HEALTH_STATUS_EXTENDED_OPERATION_MODE = 2; + + /** Health status is in test mode. */ + public static final int HEALTH_STATUS_IN_TEST = 3; + /** E1-B data validity status. */ - private int mDataValidityStatusE1b; + private @GalileoDataValidityStatus int mDataValidityStatusE1b; /** E1-B/C signal health status. */ - private int mSignalHealthStatusE1b; + private @GalileoHealthStatus int mSignalHealthStatusE1b; /** E5a data validity status. */ - private int mDataValidityStatusE5a; + private @GalileoDataValidityStatus int mDataValidityStatusE5a; /** E5a signal health status. */ - private int mSignalHealthStatusE5a; + private @GalileoHealthStatus int mSignalHealthStatusE5a; /** E5b data validity status. */ - private int mDataValidityStatusE5b; + private @GalileoDataValidityStatus int mDataValidityStatusE5b; /** E5b signal health status. */ - private int mSignalHealthStatusE5b; + private @GalileoHealthStatus int mSignalHealthStatusE5b; private GalileoSvHealth(Builder builder) { Preconditions.checkArgumentInRange( - builder.mDataValidityStatusE1b, 0, 1, "DataValidityStatusE1b"); + builder.mDataValidityStatusE1b, + DATA_STATUS_DATA_VALID, + DATA_STATUS_WORKING_WITHOUT_GUARANTEE, + "DataValidityStatusE1b"); Preconditions.checkArgumentInRange( - builder.mSignalHealthStatusE1b, 0, 3, "SignalHealthStatusE1b"); + builder.mSignalHealthStatusE1b, + HEALTH_STATUS_OK, + HEALTH_STATUS_IN_TEST, + "SignalHealthStatusE1b"); Preconditions.checkArgumentInRange( - builder.mDataValidityStatusE5a, 0, 1, "DataValidityStatusE5a"); + builder.mDataValidityStatusE5a, + DATA_STATUS_DATA_VALID, + DATA_STATUS_WORKING_WITHOUT_GUARANTEE, + "DataValidityStatusE5a"); Preconditions.checkArgumentInRange( - builder.mSignalHealthStatusE5a, 0, 3, "SignalHealthStatusE5a"); + builder.mSignalHealthStatusE5a, + HEALTH_STATUS_OK, + HEALTH_STATUS_IN_TEST, + "SignalHealthStatusE5a"); Preconditions.checkArgumentInRange( - builder.mDataValidityStatusE5b, 0, 1, "DataValidityStatusE5b"); + builder.mDataValidityStatusE5b, + DATA_STATUS_DATA_VALID, + DATA_STATUS_WORKING_WITHOUT_GUARANTEE, + "DataValidityStatusE5b"); Preconditions.checkArgumentInRange( - builder.mSignalHealthStatusE5b, 0, 3, "SignalHealthStatusE5b"); + builder.mSignalHealthStatusE5b, + HEALTH_STATUS_OK, + HEALTH_STATUS_IN_TEST, + "SignalHealthStatusE5b"); mDataValidityStatusE1b = builder.mDataValidityStatusE1b; mSignalHealthStatusE1b = builder.mSignalHealthStatusE1b; mDataValidityStatusE5a = builder.mDataValidityStatusE5a; @@ -258,37 +327,37 @@ public final class GalileoSatelliteEphemeris implements Parcelable { } /** Returns the E1-B data validity status. */ - @IntRange(from = 0, to = 1) + @GalileoDataValidityStatus public int getDataValidityStatusE1b() { return mDataValidityStatusE1b; } /** Returns the E1-B/C signal health status. */ - @IntRange(from = 0, to = 3) + @GalileoHealthStatus public int getSignalHealthStatusE1b() { return mSignalHealthStatusE1b; } /** Returns the E5a data validity status. */ - @IntRange(from = 0, to = 1) + @GalileoDataValidityStatus public int getDataValidityStatusE5a() { return mDataValidityStatusE5a; } /** Returns the E5a signal health status. */ - @IntRange(from = 0, to = 3) + @GalileoHealthStatus public int getSignalHealthStatusE5a() { return mSignalHealthStatusE5a; } /** Returns the E5b data validity status. */ - @IntRange(from = 0, to = 1) + @GalileoDataValidityStatus public int getDataValidityStatusE5b() { return mDataValidityStatusE5b; } /** Returns the E5b signal health status. */ - @IntRange(from = 0, to = 3) + @GalileoHealthStatus public int getSignalHealthStatusE5b() { return mSignalHealthStatusE5b; } @@ -355,7 +424,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E1-B data validity status. */ @NonNull public Builder setDataValidityStatusE1b( - @IntRange(from = 0, to = 1) int dataValidityStatusE1b) { + @GalileoDataValidityStatus int dataValidityStatusE1b) { mDataValidityStatusE1b = dataValidityStatusE1b; return this; } @@ -363,7 +432,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E1-B/C signal health status. */ @NonNull public Builder setSignalHealthStatusE1b( - @IntRange(from = 0, to = 3) int signalHealthStatusE1b) { + @GalileoHealthStatus int signalHealthStatusE1b) { mSignalHealthStatusE1b = signalHealthStatusE1b; return this; } @@ -371,7 +440,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E5a data validity status. */ @NonNull public Builder setDataValidityStatusE5a( - @IntRange(from = 0, to = 1) int dataValidityStatusE5a) { + @GalileoDataValidityStatus int dataValidityStatusE5a) { mDataValidityStatusE5a = dataValidityStatusE5a; return this; } @@ -379,7 +448,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E5a signal health status. */ @NonNull public Builder setSignalHealthStatusE5a( - @IntRange(from = 0, to = 3) int signalHealthStatusE5a) { + @GalileoHealthStatus int signalHealthStatusE5a) { mSignalHealthStatusE5a = signalHealthStatusE5a; return this; } @@ -387,7 +456,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E5b data validity status. */ @NonNull public Builder setDataValidityStatusE5b( - @IntRange(from = 0, to = 1) int dataValidityStatusE5b) { + @GalileoDataValidityStatus int dataValidityStatusE5b) { mDataValidityStatusE5b = dataValidityStatusE5b; return this; } @@ -395,7 +464,7 @@ public final class GalileoSatelliteEphemeris implements Parcelable { /** Sets the E5b signal health status. */ @NonNull public Builder setSignalHealthStatusE5b( - @IntRange(from = 0, to = 3) int signalHealthStatusE5b) { + @GalileoHealthStatus int signalHealthStatusE5b) { mSignalHealthStatusE5b = signalHealthStatusE5b; return this; } diff --git a/location/java/android/location/GlonassAlmanac.java b/location/java/android/location/GlonassAlmanac.java index 861dc5d257c4..37657435b98a 100644 --- a/location/java/android/location/GlonassAlmanac.java +++ b/location/java/android/location/GlonassAlmanac.java @@ -21,6 +21,7 @@ import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.location.GlonassSatelliteEphemeris.GlonassHealthStatus; import android.location.flags.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -121,11 +122,17 @@ public final class GlonassAlmanac implements Parcelable { /** Slot number. */ private final int mSlotNumber; - /** Satellite health information (0=healthy, 1=unhealthy). */ - private final int mSvHealth; + /** Satellite health status. */ + private final @GlonassHealthStatus int mHealthState; /** Frequency channel number. */ - private final int mFreqChannel; + private final int mFrequencyChannelNumber; + + /** Calendar day number within the four-year period beginning since the leap year. */ + private final int mCalendarDayNumber; + + /** Flag to indicates if the satellite is a GLONASS-M satellitee. */ + private final boolean mGlonassM; /** Coarse value of satellite time correction to GLONASS time in seconds. */ private final double mTau; @@ -148,15 +155,18 @@ public final class GlonassAlmanac implements Parcelable { /** Eccentricity. */ private final double mEccentricity; - /** Argument of perigee in radians. */ + /** Argument of perigee in semi-circles. */ private final double mOmega; private GlonassSatelliteAlmanac(Builder builder) { // Allow slotNumber beyond the range to support potential future extensibility. Preconditions.checkArgument(builder.mSlotNumber >= 1); - // Allow svHealth beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mSvHealth >= 0); - Preconditions.checkArgumentInRange(builder.mFreqChannel, 0, 31, "FreqChannel"); + // Allow healthState beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mHealthState >= 0); + Preconditions.checkArgumentInRange( + builder.mFrequencyChannelNumber, 0, 31, "FrequencyChannelNumber"); + Preconditions.checkArgumentInRange( + builder.mCalendarDayNumber, 1, 1461, "CalendarDayNumber"); Preconditions.checkArgumentInRange(builder.mTau, -1.9e-3f, 1.9e-3f, "Tau"); Preconditions.checkArgumentInRange(builder.mTLambda, 0.0f, 44100.0f, "TLambda"); Preconditions.checkArgumentInRange(builder.mLambda, -1.0f, 1.0f, "Lambda"); @@ -166,8 +176,10 @@ public final class GlonassAlmanac implements Parcelable { Preconditions.checkArgumentInRange(builder.mEccentricity, 0.0f, 0.03f, "Eccentricity"); Preconditions.checkArgumentInRange(builder.mOmega, -1.0f, 1.0f, "Omega"); mSlotNumber = builder.mSlotNumber; - mSvHealth = builder.mSvHealth; - mFreqChannel = builder.mFreqChannel; + mHealthState = builder.mHealthState; + mFrequencyChannelNumber = builder.mFrequencyChannelNumber; + mCalendarDayNumber = builder.mCalendarDayNumber; + mGlonassM = builder.mGlonassM; mTau = builder.mTau; mTLambda = builder.mTLambda; mLambda = builder.mLambda; @@ -184,16 +196,29 @@ public final class GlonassAlmanac implements Parcelable { return mSlotNumber; } - /** Returns the Satellite health information (0=healthy, 1=unhealthy). */ - @IntRange(from = 0, to = 1) - public int getSvHealth() { - return mSvHealth; + /** Returns the satellite health status. */ + public @GlonassHealthStatus int getHealthState() { + return mHealthState; } /** Returns the frequency channel number. */ @IntRange(from = 0, to = 31) - public int getFreqChannel() { - return mFreqChannel; + public int getFrequencyChannelNumber() { + return mFrequencyChannelNumber; + } + + /** + * Returns the calendar day number within the four-year period beginning since the leap + * year. + */ + @IntRange(from = 1, to = 1461) + public int getCalendarDayNumber() { + return mCalendarDayNumber; + } + + /** Returns true if the satellite is a GLONASS-M satellitee, false otherwise. */ + public boolean isGlonassM() { + return mGlonassM; } /** Returns the coarse value of satellite time correction to GLONASS time in seconds. */ @@ -241,7 +266,7 @@ public final class GlonassAlmanac implements Parcelable { return mEccentricity; } - /** Returns the argument of perigee in radians. */ + /** Returns the Argument of perigee in semi-circles. */ @FloatRange(from = -1.0f, to = 1.0f) public double getOmega() { return mOmega; @@ -255,8 +280,10 @@ public final class GlonassAlmanac implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSlotNumber); - dest.writeInt(mSvHealth); - dest.writeInt(mFreqChannel); + dest.writeInt(mHealthState); + dest.writeInt(mFrequencyChannelNumber); + dest.writeInt(mCalendarDayNumber); + dest.writeBoolean(mGlonassM); dest.writeDouble(mTau); dest.writeDouble(mTLambda); dest.writeDouble(mLambda); @@ -273,8 +300,10 @@ public final class GlonassAlmanac implements Parcelable { public GlonassSatelliteAlmanac createFromParcel(@NonNull Parcel source) { return new GlonassSatelliteAlmanac.Builder() .setSlotNumber(source.readInt()) - .setSvHealth(source.readInt()) - .setFreqChannel(source.readInt()) + .setHealthState(source.readInt()) + .setFrequencyChannelNumber(source.readInt()) + .setCalendarDayNumber(source.readInt()) + .setGlonassM(source.readBoolean()) .setTau(source.readDouble()) .setTLambda(source.readDouble()) .setLambda(source.readDouble()) @@ -297,8 +326,10 @@ public final class GlonassAlmanac implements Parcelable { public String toString() { StringBuilder builder = new StringBuilder("GlonassSatelliteAlmanac["); builder.append("slotNumber = ").append(mSlotNumber); - builder.append(", svHealth = ").append(mSvHealth); - builder.append(", freqChannel = ").append(mFreqChannel); + builder.append(", healthState = ").append(mHealthState); + builder.append(", frequencyChannelNumber = ").append(mFrequencyChannelNumber); + builder.append(", calendarDayNumber = ").append(mCalendarDayNumber); + builder.append(", glonassM = ").append(mGlonassM); builder.append(", tau = ").append(mTau); builder.append(", tLambda = ").append(mTLambda); builder.append(", lambda = ").append(mLambda); @@ -314,8 +345,10 @@ public final class GlonassAlmanac implements Parcelable { /** Builder for {@link GlonassSatelliteAlmanac}. */ public static final class Builder { private int mSlotNumber; - private int mSvHealth; - private int mFreqChannel; + private int mHealthState; + private int mFrequencyChannelNumber; + private int mCalendarDayNumber; + private boolean mGlonassM; private double mTau; private double mTLambda; private double mLambda; @@ -332,17 +365,36 @@ public final class GlonassAlmanac implements Parcelable { return this; } - /** Sets the Satellite health information (0=healthy, 1=unhealthy). */ + /** Sets the satellite health status. */ @NonNull - public Builder setSvHealth(@IntRange(from = 0, to = 1) int svHealth) { - mSvHealth = svHealth; + public Builder setHealthState(@GlonassHealthStatus int healthState) { + mHealthState = healthState; return this; } /** Sets the frequency channel number. */ @NonNull - public Builder setFreqChannel(@IntRange(from = 0, to = 31) int freqChannel) { - mFreqChannel = freqChannel; + public Builder setFrequencyChannelNumber( + @IntRange(from = 0, to = 31) int frequencyChannelNumber) { + mFrequencyChannelNumber = frequencyChannelNumber; + return this; + } + + /** + * Sets the calendar day number within the four-year period beginning since the leap + * year. + */ + @NonNull + public Builder setCalendarDayNumber( + @IntRange(from = 1, to = 1461) int calendarDayNumber) { + mCalendarDayNumber = calendarDayNumber; + return this; + } + + /** Sets to true if the satellite is a GLONASS-M satellitee, false otherwise. */ + @NonNull + public Builder setGlonassM(boolean isGlonassM) { + this.mGlonassM = isGlonassM; return this; } @@ -401,7 +453,7 @@ public final class GlonassAlmanac implements Parcelable { return this; } - /** Sets the argument of perigee in radians. */ + /** Sets the Argument of perigee in semi-circles. */ @NonNull public Builder setOmega(@FloatRange(from = -1.0f, to = 1.0f) double omega) { mOmega = omega; diff --git a/location/java/android/location/GlonassAssistance.java b/location/java/android/location/GlonassAssistance.java index cc0820197d8d..c7ed1c52b403 100644 --- a/location/java/android/location/GlonassAssistance.java +++ b/location/java/android/location/GlonassAssistance.java @@ -19,7 +19,6 @@ package android.location; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.location.GnssAssistance.GnssSatelliteCorrections; import android.location.flags.Flags; @@ -45,6 +44,9 @@ public final class GlonassAssistance implements Parcelable { /** The UTC model. */ @Nullable private final UtcModel mUtcModel; + /** The auxiliary information. */ + @Nullable private final AuxiliaryInformation mAuxiliaryInformation; + /** The list of time models. */ @NonNull private final List<TimeModel> mTimeModels; @@ -57,6 +59,7 @@ public final class GlonassAssistance implements Parcelable { private GlonassAssistance(Builder builder) { mAlmanac = builder.mAlmanac; mUtcModel = builder.mUtcModel; + mAuxiliaryInformation = builder.mAuxiliaryInformation; if (builder.mTimeModels != null) { mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); } else { @@ -106,6 +109,12 @@ public final class GlonassAssistance implements Parcelable { return mSatelliteCorrections; } + /** Returns the auxiliary information. */ + @Nullable + public AuxiliaryInformation getAuxiliaryInformation() { + return mAuxiliaryInformation; + } + @Override public int describeContents() { return 0; @@ -115,6 +124,7 @@ public final class GlonassAssistance implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeTypedObject(mAlmanac, flags); dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedObject(mAuxiliaryInformation, flags); dest.writeTypedList(mTimeModels); dest.writeTypedList(mSatelliteEphemeris); dest.writeTypedList(mSatelliteCorrections); @@ -126,6 +136,7 @@ public final class GlonassAssistance implements Parcelable { StringBuilder builder = new StringBuilder("GlonassAssistance["); builder.append("almanac = ").append(mAlmanac); builder.append(", utcModel = ").append(mUtcModel); + builder.append(", auxiliaryInformation = ").append(mAuxiliaryInformation); builder.append(", timeModels = ").append(mTimeModels); builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); @@ -140,6 +151,8 @@ public final class GlonassAssistance implements Parcelable { return new GlonassAssistance.Builder() .setAlmanac(in.readTypedObject(GlonassAlmanac.CREATOR)) .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setAuxiliaryInformation( + in.readTypedObject(AuxiliaryInformation.CREATOR)) .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) .setSatelliteEphemeris( in.createTypedArrayList(GlonassSatelliteEphemeris.CREATOR)) @@ -158,30 +171,36 @@ public final class GlonassAssistance implements Parcelable { public static final class Builder { private GlonassAlmanac mAlmanac; private UtcModel mUtcModel; + private AuxiliaryInformation mAuxiliaryInformation; private List<TimeModel> mTimeModels; private List<GlonassSatelliteEphemeris> mSatelliteEphemeris; private List<GnssSatelliteCorrections> mSatelliteCorrections; /** Sets the Glonass almanac. */ @NonNull - public Builder setAlmanac( - @Nullable @SuppressLint("NullableCollection") GlonassAlmanac almanac) { + public Builder setAlmanac(@Nullable GlonassAlmanac almanac) { mAlmanac = almanac; return this; } /** Sets the UTC model. */ @NonNull - public Builder setUtcModel( - @Nullable @SuppressLint("NullableCollection") UtcModel utcModel) { + public Builder setUtcModel(@Nullable UtcModel utcModel) { mUtcModel = utcModel; return this; } + /** Sets the auxiliary information. */ + @NonNull + public Builder setAuxiliaryInformation( + @Nullable AuxiliaryInformation auxiliaryInformation) { + mAuxiliaryInformation = auxiliaryInformation; + return this; + } + /** Sets the list of time models. */ @NonNull - public Builder setTimeModels( - @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + public Builder setTimeModels(@NonNull List<TimeModel> timeModels) { mTimeModels = timeModels; return this; } @@ -189,8 +208,7 @@ public final class GlonassAssistance implements Parcelable { /** Sets the list of Glonass satellite ephemeris. */ @NonNull public Builder setSatelliteEphemeris( - @Nullable @SuppressLint("NullableCollection") - List<GlonassSatelliteEphemeris> satelliteEphemeris) { + @NonNull List<GlonassSatelliteEphemeris> satelliteEphemeris) { mSatelliteEphemeris = satelliteEphemeris; return this; } @@ -198,8 +216,7 @@ public final class GlonassAssistance implements Parcelable { /** Sets the list of Glonass satellite corrections. */ @NonNull public Builder setSatelliteCorrections( - @Nullable @SuppressLint("NullableCollection") - List<GnssSatelliteCorrections> satelliteCorrections) { + @NonNull List<GnssSatelliteCorrections> satelliteCorrections) { mSatelliteCorrections = satelliteCorrections; return this; } diff --git a/location/java/android/location/GlonassSatelliteEphemeris.java b/location/java/android/location/GlonassSatelliteEphemeris.java index 77a6ebb50cfb..bee6047f71c8 100644 --- a/location/java/android/location/GlonassSatelliteEphemeris.java +++ b/location/java/android/location/GlonassSatelliteEphemeris.java @@ -18,6 +18,7 @@ package android.location; import android.annotation.FlaggedApi; import android.annotation.FloatRange; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -27,6 +28,9 @@ import android.os.Parcelable; import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * A class contains ephemeris parameters specific to Glonass satellites. * @@ -38,11 +42,31 @@ import com.android.internal.util.Preconditions; @SystemApi public final class GlonassSatelliteEphemeris implements Parcelable { + /** + * Glonass signal health status. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({HEALTH_STATUS_HEALTHY, HEALTH_STATUS_UNHEALTHY}) + public @interface GlonassHealthStatus {} + + /** + * The following enumerations must be in sync with the values declared in + * GlonassSatelliteEphemeris.aidl + */ + + /** Health status is healthy. */ + public static final int HEALTH_STATUS_HEALTHY = 0; + + /** Health status is unhealthy. */ + public static final int HEALTH_STATUS_UNHEALTHY = 1; + /** L1/Satellite system (R), satellite number (slot number in sat. constellation). */ private final int mSlotNumber; - /** Health state (0=healthy, 1=unhealthy). */ - private final int mHealthState; + /** Health state. */ + private final @GlonassHealthStatus int mHealthState; /** Message frame time in seconds of the UTC week (tk+nd*86400). */ private final double mFrameTimeSeconds; @@ -50,6 +74,15 @@ public final class GlonassSatelliteEphemeris implements Parcelable { /** Age of current information in days (E). */ private final int mAgeInDays; + /** Update and validity interval in minutes (P1) */ + private final int mUpdateIntervalMinutes; + + /** Flag to indicate if the update interval is odd or even (P2). */ + private final boolean mUpdateIntervalOdd; + + /** Flag to indicates if the satellite is a Glonass-M satellitee (M). */ + private final boolean mGlonassM; + /** Satellite clock model. */ @NonNull private final GlonassSatelliteClockModel mSatelliteClockModel; @@ -63,6 +96,8 @@ public final class GlonassSatelliteEphemeris implements Parcelable { Preconditions.checkArgument(builder.mHealthState >= 0); Preconditions.checkArgument(builder.mFrameTimeSeconds >= 0.0f); Preconditions.checkArgumentInRange(builder.mAgeInDays, 0, 31, "AgeInDays"); + Preconditions.checkArgumentInRange( + builder.mUpdateIntervalMinutes, 0, 60, "UpdateIntervalMinutes"); Preconditions.checkNotNull( builder.mSatelliteClockModel, "SatelliteClockModel cannot be null"); Preconditions.checkNotNull( @@ -71,6 +106,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { mHealthState = builder.mHealthState; mFrameTimeSeconds = builder.mFrameTimeSeconds; mAgeInDays = builder.mAgeInDays; + mUpdateIntervalMinutes = builder.mUpdateIntervalMinutes; + mUpdateIntervalOdd = builder.mUpdateIntervalOdd; + mGlonassM = builder.mGlonassM; mSatelliteClockModel = builder.mSatelliteClockModel; mSatelliteOrbitModel = builder.mSatelliteOrbitModel; } @@ -83,9 +121,8 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return mSlotNumber; } - /** Returns the health state (0=healthy, 1=unhealthy). */ - @IntRange(from = 0, to = 1) - public int getHealthState() { + /** Returns the health state. */ + public @GlonassHealthStatus int getHealthState() { return mHealthState; } @@ -101,6 +138,22 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return mAgeInDays; } + /** Returns the update interval in minutes (P1). */ + @IntRange(from = 0, to = 60) + public int getUpdateIntervalMinutes() { + return mUpdateIntervalMinutes; + } + + /** Returns true if the update interval (P2) is odd, false otherwise (P2). */ + public boolean isUpdateIntervalOdd() { + return mUpdateIntervalOdd; + } + + /** Returns true if the satellite is a Glonass-M satellitee (M), false otherwise. */ + public boolean isGlonassM() { + return mGlonassM; + } + /** Returns the satellite clock model. */ @NonNull public GlonassSatelliteClockModel getSatelliteClockModel() { @@ -124,6 +177,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { dest.writeInt(mHealthState); dest.writeDouble(mFrameTimeSeconds); dest.writeInt(mAgeInDays); + dest.writeInt(mUpdateIntervalMinutes); + dest.writeBoolean(mUpdateIntervalOdd); + dest.writeBoolean(mGlonassM); dest.writeTypedObject(mSatelliteClockModel, flags); dest.writeTypedObject(mSatelliteOrbitModel, flags); } @@ -137,6 +193,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { .setHealthState(source.readInt()) .setFrameTimeSeconds(source.readDouble()) .setAgeInDays(source.readInt()) + .setUpdateIntervalMinutes(source.readInt()) + .setUpdateIntervalOdd(source.readBoolean()) + .setGlonassM(source.readBoolean()) .setSatelliteClockModel( source.readTypedObject(GlonassSatelliteClockModel.CREATOR)) .setSatelliteOrbitModel( @@ -158,6 +217,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { builder.append(", healthState = ").append(mHealthState); builder.append(", frameTimeSeconds = ").append(mFrameTimeSeconds); builder.append(", ageInDays = ").append(mAgeInDays); + builder.append(", updateIntervalMinutes = ").append(mUpdateIntervalMinutes); + builder.append(", isUpdateIntervalOdd = ").append(mUpdateIntervalOdd); + builder.append(", isGlonassM = ").append(mGlonassM); builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); builder.append("]"); @@ -170,6 +232,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { private int mHealthState; private double mFrameTimeSeconds; private int mAgeInDays; + private int mUpdateIntervalMinutes; + private boolean mUpdateIntervalOdd; + private boolean mGlonassM; private GlonassSatelliteClockModel mSatelliteClockModel; private GlonassSatelliteOrbitModel mSatelliteOrbitModel; @@ -182,9 +247,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return this; } - /** Sets the health state (0=healthy, 1=unhealthy). */ + /** Sets the health state. */ @NonNull - public Builder setHealthState(@IntRange(from = 0, to = 1) int healthState) { + public Builder setHealthState(@GlonassHealthStatus int healthState) { mHealthState = healthState; return this; } @@ -219,6 +284,28 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return this; } + /** Sets the update interval in minutes (P1). */ + @NonNull + public Builder setUpdateIntervalMinutes( + @IntRange(from = 0, to = 60) int updateIntervalMinutes) { + mUpdateIntervalMinutes = updateIntervalMinutes; + return this; + } + + /** Sets to true if the update interval (P2) is odd, false otherwise. */ + @NonNull + public Builder setUpdateIntervalOdd(boolean isUpdateIntervalOdd) { + mUpdateIntervalOdd = isUpdateIntervalOdd; + return this; + } + + /** Sets to true if the satellite is a Glonass-M satellitee (M), false otherwise. */ + @NonNull + public Builder setGlonassM(boolean isGlonassM) { + mGlonassM = isGlonassM; + return this; + } + /** Builds a {@link GlonassSatelliteEphemeris}. */ @NonNull public GlonassSatelliteEphemeris build() { @@ -246,19 +333,36 @@ public final class GlonassSatelliteEphemeris implements Parcelable { /** Frequency bias (+GammaN). */ private final double mFrequencyBias; - /** Frequency number. */ - private final int mFrequencyNumber; + /** Frequency channel number. */ + private final int mFrequencyChannelNumber; + + /* L1/L2 group delay difference in seconds (DeltaTau). */ + private final double mGroupDelayDiffSeconds; + + /** + * Whether the L1/L2 group delay difference in seconds (DeltaTau) is available. + * + * <p>It is set to true if available, otherwise false. + */ + private final boolean mGroupDelayDiffSecondsAvailable; private GlonassSatelliteClockModel(Builder builder) { Preconditions.checkArgument(builder.mTimeOfClockSeconds >= 0); Preconditions.checkArgumentInRange(builder.mClockBias, -0.002f, 0.002f, "ClockBias"); Preconditions.checkArgumentInRange( builder.mFrequencyBias, -9.32e-10f, 9.32e-10f, "FrequencyBias"); - Preconditions.checkArgumentInRange(builder.mFrequencyNumber, -7, 6, "FrequencyNumber"); + Preconditions.checkArgumentInRange( + builder.mFrequencyChannelNumber, -7, 6, "FrequencyChannelNumber"); + if (builder.mGroupDelayDiffSecondsAvailable) { + Preconditions.checkArgumentInRange( + builder.mGroupDelayDiffSeconds, -1.4e-8f, 1.4e-8f, "GroupDelayDiffSeconds"); + } mTimeOfClockSeconds = builder.mTimeOfClockSeconds; mClockBias = builder.mClockBias; mFrequencyBias = builder.mFrequencyBias; - mFrequencyNumber = builder.mFrequencyNumber; + mFrequencyChannelNumber = builder.mFrequencyChannelNumber; + mGroupDelayDiffSeconds = builder.mGroupDelayDiffSeconds; + mGroupDelayDiffSecondsAvailable = builder.mGroupDelayDiffSecondsAvailable; } /** Returns the time of clock in seconds (UTC). */ @@ -279,10 +383,21 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return mFrequencyBias; } - /** Returns the frequency number. */ + /** Returns the Frequency channel number. */ @IntRange(from = -7, to = 6) - public int getFrequencyNumber() { - return mFrequencyNumber; + public int getFrequencyChannelNumber() { + return mFrequencyChannelNumber; + } + + /** Returns the L1/L2 group delay difference in seconds (DeltaTau). */ + @FloatRange(from = -1.4e-8f, to = 1.4e-8f) + public double getGroupDelayDiffSeconds() { + return mGroupDelayDiffSeconds; + } + + /** Returns whether the L1/L2 group delay difference in seconds (DeltaTau) is available. */ + public boolean isGroupDelayDiffSecondsAvailable() { + return mGroupDelayDiffSecondsAvailable; } @Override @@ -295,7 +410,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { dest.writeLong(mTimeOfClockSeconds); dest.writeDouble(mClockBias); dest.writeDouble(mFrequencyBias); - dest.writeInt(mFrequencyNumber); + dest.writeInt(mFrequencyChannelNumber); + dest.writeDouble(mGroupDelayDiffSeconds); + dest.writeBoolean(mGroupDelayDiffSecondsAvailable); } public static final @NonNull Parcelable.Creator<GlonassSatelliteClockModel> CREATOR = @@ -306,7 +423,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { .setTimeOfClockSeconds(source.readLong()) .setClockBias(source.readDouble()) .setFrequencyBias(source.readDouble()) - .setFrequencyNumber(source.readInt()) + .setFrequencyChannelNumber(source.readInt()) + .setGroupDelayDiffSeconds(source.readDouble()) + .setGroupDelayDiffSecondsAvailable(source.readBoolean()) .build(); } @@ -323,7 +442,10 @@ public final class GlonassSatelliteEphemeris implements Parcelable { builder.append("timeOfClockSeconds = ").append(mTimeOfClockSeconds); builder.append(", clockBias = ").append(mClockBias); builder.append(", frequencyBias = ").append(mFrequencyBias); - builder.append(", frequencyNumber = ").append(mFrequencyNumber); + builder.append(", frequencyChannelNumber = ").append(mFrequencyChannelNumber); + if (mGroupDelayDiffSecondsAvailable) { + builder.append(", groupDelayDiffSeconds = ").append(mGroupDelayDiffSeconds); + } builder.append("]"); return builder.toString(); } @@ -333,7 +455,9 @@ public final class GlonassSatelliteEphemeris implements Parcelable { private long mTimeOfClockSeconds; private double mClockBias; private double mFrequencyBias; - private int mFrequencyNumber; + private double mGroupDelayDiffSeconds; + private int mFrequencyChannelNumber; + private boolean mGroupDelayDiffSecondsAvailable; /** Sets the time of clock in seconds (UTC). */ @NonNull @@ -357,10 +481,27 @@ public final class GlonassSatelliteEphemeris implements Parcelable { return this; } - /** Sets the frequency number. */ + /** Sets the Frequency channel number. */ + @NonNull + public Builder setFrequencyChannelNumber( + @IntRange(from = -7, to = 6) int frequencyChannelNumber) { + mFrequencyChannelNumber = frequencyChannelNumber; + return this; + } + + /** Sets the L1/L2 group delay difference in seconds (DeltaTau). */ + @NonNull + public Builder setGroupDelayDiffSeconds( + @FloatRange(from = -1.4e-8f, to = 1.4e-8f) double groupDelayDiffSeconds) { + mGroupDelayDiffSeconds = groupDelayDiffSeconds; + return this; + } + + /** Sets whether the L1/L2 group delay difference in seconds (DeltaTau) is available. */ @NonNull - public Builder setFrequencyNumber(@IntRange(from = -7, to = 6) int frequencyNumber) { - mFrequencyNumber = frequencyNumber; + public Builder setGroupDelayDiffSecondsAvailable( + boolean isGroupDelayDiffSecondsAvailable) { + mGroupDelayDiffSecondsAvailable = isGroupDelayDiffSecondsAvailable; return this; } diff --git a/location/java/android/location/GnssAlmanac.java b/location/java/android/location/GnssAlmanac.java index 6466e45a965e..c16ad91f130a 100644 --- a/location/java/android/location/GnssAlmanac.java +++ b/location/java/android/location/GnssAlmanac.java @@ -59,7 +59,7 @@ public final class GnssAlmanac implements Parcelable { * * <p>This is unused for GPS/QZSS/Baidou. */ - private final int mIod; + private final int mIoda; /** * Almanac reference week number. @@ -75,20 +75,27 @@ public final class GnssAlmanac implements Parcelable { /** Almanac reference time in seconds. */ private final int mToaSeconds; + /** + * Flag to indicate if the satelliteAlmanacs contains complete GNSS + * constellation indicated by svid. + */ + private final boolean mCompleteAlmanacProvided; + /** The list of GnssSatelliteAlmanacs. */ @NonNull private final List<GnssSatelliteAlmanac> mGnssSatelliteAlmanacs; private GnssAlmanac(Builder builder) { Preconditions.checkArgument(builder.mIssueDateMillis >= 0); - Preconditions.checkArgument(builder.mIod >= 0); + Preconditions.checkArgument(builder.mIoda >= 0); Preconditions.checkArgument(builder.mWeekNumber >= 0); Preconditions.checkArgumentInRange(builder.mToaSeconds, 0, 604800, "ToaSeconds"); Preconditions.checkNotNull( builder.mGnssSatelliteAlmanacs, "GnssSatelliteAlmanacs cannot be null"); mIssueDateMillis = builder.mIssueDateMillis; - mIod = builder.mIod; + mIoda = builder.mIoda; mWeekNumber = builder.mWeekNumber; mToaSeconds = builder.mToaSeconds; + mCompleteAlmanacProvided = builder.mCompleteAlmanacProvided; mGnssSatelliteAlmanacs = Collections.unmodifiableList(new ArrayList<>(builder.mGnssSatelliteAlmanacs)); } @@ -101,8 +108,8 @@ public final class GnssAlmanac implements Parcelable { /** Returns the almanac issue of data. */ @IntRange(from = 0) - public int getIod() { - return mIod; + public int getIoda() { + return mIoda; } /** @@ -125,6 +132,14 @@ public final class GnssAlmanac implements Parcelable { return mToaSeconds; } + /** + * Returns the flag to indicate if the satelliteAlmanacs contains complete GNSS + * constellation indicated by svid. + */ + public boolean isCompleteAlmanacProvided() { + return mCompleteAlmanacProvided; + } + /** Returns the list of GnssSatelliteAlmanacs. */ @NonNull public List<GnssSatelliteAlmanac> getGnssSatelliteAlmanacs() { @@ -139,9 +154,10 @@ public final class GnssAlmanac implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(mIssueDateMillis); - dest.writeInt(mIod); + dest.writeInt(mIoda); dest.writeInt(mWeekNumber); dest.writeInt(mToaSeconds); + dest.writeBoolean(mCompleteAlmanacProvided); dest.writeTypedList(mGnssSatelliteAlmanacs); } @@ -151,9 +167,10 @@ public final class GnssAlmanac implements Parcelable { public GnssAlmanac createFromParcel(Parcel in) { GnssAlmanac.Builder gnssAlmanac = new GnssAlmanac.Builder(); gnssAlmanac.setIssueDateMillis(in.readLong()); - gnssAlmanac.setIod(in.readInt()); + gnssAlmanac.setIoda(in.readInt()); gnssAlmanac.setWeekNumber(in.readInt()); gnssAlmanac.setToaSeconds(in.readInt()); + gnssAlmanac.setCompleteAlmanacProvided(in.readBoolean()); List<GnssSatelliteAlmanac> satelliteAlmanacs = new ArrayList<>(); in.readTypedList(satelliteAlmanacs, GnssSatelliteAlmanac.CREATOR); gnssAlmanac.setGnssSatelliteAlmanacs(satelliteAlmanacs); @@ -170,9 +187,10 @@ public final class GnssAlmanac implements Parcelable { public String toString() { StringBuilder builder = new StringBuilder("GnssAlmanac["); builder.append("issueDateMillis=").append(mIssueDateMillis); - builder.append(", iod=").append(mIod); + builder.append(", ioda=").append(mIoda); builder.append(", weekNumber=").append(mWeekNumber); builder.append(", toaSeconds=").append(mToaSeconds); + builder.append(", completeAlmanacProvided=").append(mCompleteAlmanacProvided); builder.append(", satelliteAlmanacs=").append(mGnssSatelliteAlmanacs); builder.append("]"); return builder.toString(); @@ -181,9 +199,10 @@ public final class GnssAlmanac implements Parcelable { /** Builder for {@link GnssAlmanac}. */ public static final class Builder { private long mIssueDateMillis; - private int mIod; + private int mIoda; private int mWeekNumber; private int mToaSeconds; + private boolean mCompleteAlmanacProvided; private List<GnssSatelliteAlmanac> mGnssSatelliteAlmanacs; /** Sets the almanac issue date in milliseconds (UTC). */ @@ -195,8 +214,8 @@ public final class GnssAlmanac implements Parcelable { /** Sets the almanac issue of data. */ @NonNull - public Builder setIod(@IntRange(from = 0) int iod) { - mIod = iod; + public Builder setIoda(@IntRange(from = 0) int ioda) { + mIoda = ioda; return this; } @@ -222,6 +241,16 @@ public final class GnssAlmanac implements Parcelable { return this; } + /** + * Sets to true if the satelliteAlmanacs contains complete GNSS + * constellation indicated by svid, false otherwise. + */ + @NonNull + public Builder setCompleteAlmanacProvided(boolean isCompleteAlmanacProvided) { + this.mCompleteAlmanacProvided = isCompleteAlmanacProvided; + return this; + } + /** Sets the list of GnssSatelliteAlmanacs. */ @NonNull public Builder setGnssSatelliteAlmanacs( @@ -249,7 +278,7 @@ public final class GnssAlmanac implements Parcelable { * <p>For Galileo, this is defined in Galileo-OS-SIS-ICD-v2.1 section 5.1.10. */ public static final class GnssSatelliteAlmanac implements Parcelable { - /** The PRN number of the GNSS satellite. */ + /** The PRN or satellite ID number for the GNSS satellite. */ private final int mSvid; /** @@ -332,7 +361,7 @@ public final class GnssAlmanac implements Parcelable { mAf1 = builder.mAf1; } - /** Returns the PRN number of the GNSS satellite. */ + /** Returns the PRN or satellite ID number of the GNSS satellite. */ @IntRange(from = 1) public int getSvid() { return mSvid; @@ -503,7 +532,7 @@ public final class GnssAlmanac implements Parcelable { private double mAf0; private double mAf1; - /** Sets the PRN number of the GNSS satellite. */ + /** Sets the PRN or satellite ID number of the GNSS satellite. */ @NonNull public Builder setSvid(@IntRange(from = 1) int svid) { mSvid = svid; diff --git a/location/java/android/location/GpsAssistance.java b/location/java/android/location/GpsAssistance.java index 5202fc4cd851..5a8802f057e2 100644 --- a/location/java/android/location/GpsAssistance.java +++ b/location/java/android/location/GpsAssistance.java @@ -51,6 +51,9 @@ public final class GpsAssistance implements Parcelable { /** The leap seconds model. */ @Nullable private final LeapSecondsModel mLeapSecondsModel; + /** The auxiliary information. */ + @Nullable private final AuxiliaryInformation mAuxiliaryInformation; + /** The list of time models. */ @NonNull private final List<TimeModel> mTimeModels; @@ -68,6 +71,7 @@ public final class GpsAssistance implements Parcelable { mIonosphericModel = builder.mIonosphericModel; mUtcModel = builder.mUtcModel; mLeapSecondsModel = builder.mLeapSecondsModel; + mAuxiliaryInformation = builder.mAuxiliaryInformation; if (builder.mTimeModels != null) { mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); } else { @@ -117,6 +121,12 @@ public final class GpsAssistance implements Parcelable { return mLeapSecondsModel; } + /** Returns the auxiliary information. */ + @Nullable + public AuxiliaryInformation getAuxiliaryInformation() { + return mAuxiliaryInformation; + } + /** Returns the list of time models. */ @NonNull public List<TimeModel> getTimeModels() { @@ -152,6 +162,8 @@ public final class GpsAssistance implements Parcelable { in.readTypedObject(KlobucharIonosphericModel.CREATOR)) .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setAuxiliaryInformation( + in.readTypedObject(AuxiliaryInformation.CREATOR)) .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) .setSatelliteEphemeris( in.createTypedArrayList(GpsSatelliteEphemeris.CREATOR)) @@ -179,6 +191,7 @@ public final class GpsAssistance implements Parcelable { dest.writeTypedObject(mIonosphericModel, flags); dest.writeTypedObject(mUtcModel, flags); dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedObject(mAuxiliaryInformation, flags); dest.writeTypedList(mTimeModels); dest.writeTypedList(mSatelliteEphemeris); dest.writeTypedList(mRealTimeIntegrityModels); @@ -193,6 +206,7 @@ public final class GpsAssistance implements Parcelable { builder.append(", ionosphericModel = ").append(mIonosphericModel); builder.append(", utcModel = ").append(mUtcModel); builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", auxiliaryInformation = ").append(mAuxiliaryInformation); builder.append(", timeModels = ").append(mTimeModels); builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); @@ -207,6 +221,7 @@ public final class GpsAssistance implements Parcelable { private KlobucharIonosphericModel mIonosphericModel; private UtcModel mUtcModel; private LeapSecondsModel mLeapSecondsModel; + private AuxiliaryInformation mAuxiliaryInformation; private List<TimeModel> mTimeModels; private List<GpsSatelliteEphemeris> mSatelliteEphemeris; private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; @@ -222,33 +237,36 @@ public final class GpsAssistance implements Parcelable { /** Sets the Klobuchar ionospheric model. */ @NonNull - public Builder setIonosphericModel( - @Nullable @SuppressLint("NullableCollection") - KlobucharIonosphericModel ionosphericModel) { + public Builder setIonosphericModel(@Nullable KlobucharIonosphericModel ionosphericModel) { mIonosphericModel = ionosphericModel; return this; } /** Sets the UTC model. */ @NonNull - public Builder setUtcModel( - @Nullable @SuppressLint("NullableCollection") UtcModel utcModel) { + public Builder setUtcModel(@Nullable UtcModel utcModel) { mUtcModel = utcModel; return this; } /** Sets the leap seconds model. */ @NonNull - public Builder setLeapSecondsModel( - @Nullable @SuppressLint("NullableCollection") LeapSecondsModel leapSecondsModel) { + public Builder setLeapSecondsModel(@Nullable LeapSecondsModel leapSecondsModel) { mLeapSecondsModel = leapSecondsModel; return this; } + /** Sets the auxiliary information. */ + @NonNull + public Builder setAuxiliaryInformation( + @Nullable AuxiliaryInformation auxiliaryInformation) { + mAuxiliaryInformation = auxiliaryInformation; + return this; + } + /** Sets the list of time models. */ @NonNull - public Builder setTimeModels( - @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + public Builder setTimeModels(@NonNull List<TimeModel> timeModels) { mTimeModels = timeModels; return this; } @@ -256,8 +274,7 @@ public final class GpsAssistance implements Parcelable { /** Sets the list of GPS ephemeris. */ @NonNull public Builder setSatelliteEphemeris( - @Nullable @SuppressLint("NullableCollection") - List<GpsSatelliteEphemeris> satelliteEphemeris) { + @NonNull List<GpsSatelliteEphemeris> satelliteEphemeris) { mSatelliteEphemeris = satelliteEphemeris; return this; } @@ -265,8 +282,7 @@ public final class GpsAssistance implements Parcelable { /** Sets the list of real time integrity models. */ @NonNull public Builder setRealTimeIntegrityModels( - @Nullable @SuppressLint("NullableCollection") - List<RealTimeIntegrityModel> realTimeIntegrityModels) { + @NonNull List<RealTimeIntegrityModel> realTimeIntegrityModels) { mRealTimeIntegrityModels = realTimeIntegrityModels; return this; } @@ -274,8 +290,7 @@ public final class GpsAssistance implements Parcelable { /** Sets the list of GPS satellite corrections. */ @NonNull public Builder setSatelliteCorrections( - @Nullable @SuppressLint("NullableCollection") - List<GnssSatelliteCorrections> satelliteCorrections) { + @NonNull List<GnssSatelliteCorrections> satelliteCorrections) { mSatelliteCorrections = satelliteCorrections; return this; } diff --git a/location/java/android/location/GpsSatelliteEphemeris.java b/location/java/android/location/GpsSatelliteEphemeris.java index ec6bc59dc69c..0abdc30d2f19 100644 --- a/location/java/android/location/GpsSatelliteEphemeris.java +++ b/location/java/android/location/GpsSatelliteEphemeris.java @@ -37,8 +37,8 @@ import com.android.internal.util.Preconditions; @FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) @SystemApi public final class GpsSatelliteEphemeris implements Parcelable { - /** Satellite PRN */ - private final int mPrn; + /** PRN or satellite ID number for the GPS satellite. */ + private final int mSvid; /** L2 parameters. */ @NonNull private final GpsL2Params mGpsL2Params; @@ -56,8 +56,8 @@ public final class GpsSatelliteEphemeris implements Parcelable { @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; private GpsSatelliteEphemeris(Builder builder) { - // Allow PRN beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mPrn >= 1); + // Allow svid beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); Preconditions.checkNotNull(builder.mGpsL2Params, "GPSL2Params cannot be null"); Preconditions.checkNotNull(builder.mSatelliteClockModel, "SatelliteClockModel cannot be null"); @@ -67,7 +67,7 @@ public final class GpsSatelliteEphemeris implements Parcelable { "SatelliteHealth cannot be null"); Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, "SatelliteEphemerisTime cannot be null"); - mPrn = builder.mPrn; + mSvid = builder.mSvid; mGpsL2Params = builder.mGpsL2Params; mSatelliteClockModel = builder.mSatelliteClockModel; mSatelliteOrbitModel = builder.mSatelliteOrbitModel; @@ -75,10 +75,10 @@ public final class GpsSatelliteEphemeris implements Parcelable { mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; } - /** Returns the PRN of the satellite. */ + /** Returns the svid of the satellite. */ @IntRange(from = 1, to = 32) - public int getPrn() { - return mPrn; + public int getSvid() { + return mSvid; } /** Returns the L2 parameters of the satellite. */ @@ -118,7 +118,7 @@ public final class GpsSatelliteEphemeris implements Parcelable { public GpsSatelliteEphemeris createFromParcel(Parcel in) { final GpsSatelliteEphemeris.Builder gpsSatelliteEphemeris = new Builder() - .setPrn(in.readInt()) + .setSvid(in.readInt()) .setGpsL2Params(in.readTypedObject(GpsL2Params.CREATOR)) .setSatelliteClockModel( in.readTypedObject(GpsSatelliteClockModel.CREATOR)) @@ -144,7 +144,7 @@ public final class GpsSatelliteEphemeris implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mPrn); + parcel.writeInt(mSvid); parcel.writeTypedObject(mGpsL2Params, flags); parcel.writeTypedObject(mSatelliteClockModel, flags); parcel.writeTypedObject(mSatelliteOrbitModel, flags); @@ -156,7 +156,7 @@ public final class GpsSatelliteEphemeris implements Parcelable { @NonNull public String toString() { StringBuilder builder = new StringBuilder("GpsSatelliteEphemeris["); - builder.append("prn = ").append(mPrn); + builder.append("Svid = ").append(mSvid); builder.append(", gpsL2Params = ").append(mGpsL2Params); builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); @@ -168,17 +168,17 @@ public final class GpsSatelliteEphemeris implements Parcelable { /** Builder for {@link GpsSatelliteEphemeris} */ public static final class Builder { - private int mPrn = 0; + private int mSvid = 0; private GpsL2Params mGpsL2Params; private GpsSatelliteClockModel mSatelliteClockModel; private KeplerianOrbitModel mSatelliteOrbitModel; private GpsSatelliteHealth mSatelliteHealth; private SatelliteEphemerisTime mSatelliteEphemerisTime; - /** Sets the PRN of the satellite. */ + /** Sets the PRN or satellite ID number for the GPS satellite.. */ @NonNull - public Builder setPrn(@IntRange(from = 1, to = 32) int prn) { - mPrn = prn; + public Builder setSvid(@IntRange(from = 1, to = 32) int svid) { + mSvid = svid; return this; } diff --git a/location/java/android/location/QzssAssistance.java b/location/java/android/location/QzssAssistance.java index 9383ce3c63b5..27c34370316e 100644 --- a/location/java/android/location/QzssAssistance.java +++ b/location/java/android/location/QzssAssistance.java @@ -19,7 +19,6 @@ package android.location; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.location.GnssAssistance.GnssSatelliteCorrections; import android.location.flags.Flags; @@ -51,6 +50,9 @@ public final class QzssAssistance implements Parcelable { /** The leap seconds model. */ @Nullable private final LeapSecondsModel mLeapSecondsModel; + /** The auxiliary information. */ + @Nullable private final AuxiliaryInformation mAuxiliaryInformation; + /** The list of time models. */ @NonNull private final List<TimeModel> mTimeModels; @@ -68,6 +70,7 @@ public final class QzssAssistance implements Parcelable { mIonosphericModel = builder.mIonosphericModel; mUtcModel = builder.mUtcModel; mLeapSecondsModel = builder.mLeapSecondsModel; + mAuxiliaryInformation = builder.mAuxiliaryInformation; if (builder.mTimeModels != null) { mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); } else { @@ -117,6 +120,12 @@ public final class QzssAssistance implements Parcelable { return mLeapSecondsModel; } + /** Returns the auxiliary information. */ + @Nullable + public AuxiliaryInformation getAuxiliaryInformation() { + return mAuxiliaryInformation; + } + /** Returns the list of time models. */ @NonNull public List<TimeModel> getTimeModels() { @@ -147,19 +156,23 @@ public final class QzssAssistance implements Parcelable { @NonNull public QzssAssistance createFromParcel(Parcel in) { return new QzssAssistance.Builder() - .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) - .setIonosphericModel(in.readTypedObject(KlobucharIonosphericModel.CREATOR)) - .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) - .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) - .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) - .setSatelliteEphemeris( - in.createTypedArrayList(QzssSatelliteEphemeris.CREATOR)) - .setRealTimeIntegrityModels( - in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) - .setSatelliteCorrections( - in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) - .build(); + .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) + .setIonosphericModel( + in.readTypedObject(KlobucharIonosphericModel.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setAuxiliaryInformation( + in.readTypedObject(AuxiliaryInformation.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(QzssSatelliteEphemeris.CREATOR)) + .setRealTimeIntegrityModels( + in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); } + @Override public QzssAssistance[] newArray(int size) { return new QzssAssistance[size]; @@ -177,6 +190,7 @@ public final class QzssAssistance implements Parcelable { dest.writeTypedObject(mIonosphericModel, flags); dest.writeTypedObject(mUtcModel, flags); dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedObject(mAuxiliaryInformation, flags); dest.writeTypedList(mTimeModels); dest.writeTypedList(mSatelliteEphemeris); dest.writeTypedList(mRealTimeIntegrityModels); @@ -191,6 +205,7 @@ public final class QzssAssistance implements Parcelable { builder.append(", ionosphericModel = ").append(mIonosphericModel); builder.append(", utcModel = ").append(mUtcModel); builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", auxiliaryInformation = ").append(mAuxiliaryInformation); builder.append(", timeModels = ").append(mTimeModels); builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); @@ -205,6 +220,7 @@ public final class QzssAssistance implements Parcelable { private KlobucharIonosphericModel mIonosphericModel; private UtcModel mUtcModel; private LeapSecondsModel mLeapSecondsModel; + private AuxiliaryInformation mAuxiliaryInformation; private List<TimeModel> mTimeModels; private List<QzssSatelliteEphemeris> mSatelliteEphemeris; private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; @@ -238,10 +254,17 @@ public final class QzssAssistance implements Parcelable { return this; } + /** Sets the auxiliary information. */ + @NonNull + public Builder setAuxiliaryInformation( + @Nullable AuxiliaryInformation auxiliaryInformation) { + mAuxiliaryInformation = auxiliaryInformation; + return this; + } + /** Sets the list of time models. */ @NonNull - public Builder setTimeModels( - @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + public Builder setTimeModels(@NonNull List<TimeModel> timeModels) { mTimeModels = timeModels; return this; } @@ -249,8 +272,7 @@ public final class QzssAssistance implements Parcelable { /** Sets the list of QZSS ephemeris. */ @NonNull public Builder setSatelliteEphemeris( - @Nullable @SuppressLint("NullableCollection") - List<QzssSatelliteEphemeris> satelliteEphemeris) { + @NonNull List<QzssSatelliteEphemeris> satelliteEphemeris) { mSatelliteEphemeris = satelliteEphemeris; return this; } @@ -258,8 +280,7 @@ public final class QzssAssistance implements Parcelable { /** Sets the list of real time integrity model. */ @NonNull public Builder setRealTimeIntegrityModels( - @Nullable @SuppressLint("NullableCollection") - List<RealTimeIntegrityModel> realTimeIntegrityModels) { + @NonNull List<RealTimeIntegrityModel> realTimeIntegrityModels) { mRealTimeIntegrityModels = realTimeIntegrityModels; return this; } @@ -267,8 +288,7 @@ public final class QzssAssistance implements Parcelable { /** Sets the list of QZSS satellite correction. */ @NonNull public Builder setSatelliteCorrections( - @Nullable @SuppressLint("NullableCollection") - List<GnssSatelliteCorrections> satelliteCorrections) { + @NonNull List<GnssSatelliteCorrections> satelliteCorrections) { mSatelliteCorrections = satelliteCorrections; return this; } diff --git a/location/java/android/location/QzssSatelliteEphemeris.java b/location/java/android/location/QzssSatelliteEphemeris.java index 96203d9588c8..dd9f408f53be 100644 --- a/location/java/android/location/QzssSatelliteEphemeris.java +++ b/location/java/android/location/QzssSatelliteEphemeris.java @@ -39,8 +39,8 @@ import com.android.internal.util.Preconditions; @FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) @SystemApi public final class QzssSatelliteEphemeris implements Parcelable { - /** Satellite PRN. */ - private final int mPrn; + /** PRN or satellite ID number for the Qzss satellite. */ + private final int mSvid; /** L2 parameters. */ @NonNull private final GpsL2Params mGpsL2Params; @@ -57,10 +57,10 @@ public final class QzssSatelliteEphemeris implements Parcelable { /** Ephemeris time. */ @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; - /** Returns the PRN of the satellite. */ + /** Returns the PRN or satellite ID number for the Qzss satellite. */ @IntRange(from = 183, to = 206) - public int getPrn() { - return mPrn; + public int getSvid() { + return mSvid; } /** Returns the L2 parameters of the satellite. */ @@ -95,7 +95,7 @@ public final class QzssSatelliteEphemeris implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mPrn); + parcel.writeInt(mSvid); parcel.writeTypedObject(mGpsL2Params, flags); parcel.writeTypedObject(mSatelliteClockModel, flags); parcel.writeTypedObject(mSatelliteOrbitModel, flags); @@ -104,8 +104,8 @@ public final class QzssSatelliteEphemeris implements Parcelable { } private QzssSatelliteEphemeris(Builder builder) { - // Allow PRN beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mPrn >= 1); + // Allow Svid beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); Preconditions.checkNotNull(builder.mGpsL2Params, "GpsL2Params cannot be null"); Preconditions.checkNotNull(builder.mSatelliteClockModel, "SatelliteClockModel cannot be null"); @@ -115,7 +115,7 @@ public final class QzssSatelliteEphemeris implements Parcelable { "SatelliteHealth cannot be null"); Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, "SatelliteEphemerisTime cannot be null"); - mPrn = builder.mPrn; + mSvid = builder.mSvid; mGpsL2Params = builder.mGpsL2Params; mSatelliteClockModel = builder.mSatelliteClockModel; mSatelliteOrbitModel = builder.mSatelliteOrbitModel; @@ -130,7 +130,7 @@ public final class QzssSatelliteEphemeris implements Parcelable { public QzssSatelliteEphemeris createFromParcel(Parcel in) { final QzssSatelliteEphemeris.Builder qzssSatelliteEphemeris = new Builder() - .setPrn(in.readInt()) + .setSvid(in.readInt()) .setGpsL2Params(in.readTypedObject(GpsL2Params.CREATOR)) .setSatelliteClockModel( in.readTypedObject(GpsSatelliteClockModel.CREATOR)) @@ -158,7 +158,7 @@ public final class QzssSatelliteEphemeris implements Parcelable { @NonNull public String toString() { StringBuilder builder = new StringBuilder("QzssSatelliteEphemeris["); - builder.append("prn=").append(mPrn); + builder.append("Svid=").append(mSvid); builder.append(", gpsL2Params=").append(mGpsL2Params); builder.append(", satelliteClockModel=").append(mSatelliteClockModel); builder.append(", satelliteOrbitModel=").append(mSatelliteOrbitModel); @@ -170,17 +170,17 @@ public final class QzssSatelliteEphemeris implements Parcelable { /** Builder for {@link QzssSatelliteEphemeris}. */ public static final class Builder { - private int mPrn; + private int mSvid; private GpsL2Params mGpsL2Params; private GpsSatelliteClockModel mSatelliteClockModel; private KeplerianOrbitModel mSatelliteOrbitModel; private GpsSatelliteHealth mSatelliteHealth; private SatelliteEphemerisTime mSatelliteEphemerisTime; - /** Sets the PRN of the satellite. */ + /** Sets the PRN or satellite ID number for the Qzss satellite. */ @NonNull - public Builder setPrn(@IntRange(from = 183, to = 206) int prn) { - mPrn = prn; + public Builder setSvid(@IntRange(from = 183, to = 206) int svid) { + mSvid = svid; return this; } diff --git a/location/java/android/location/RealTimeIntegrityModel.java b/location/java/android/location/RealTimeIntegrityModel.java index d268926e56e2..f065def35f7a 100644 --- a/location/java/android/location/RealTimeIntegrityModel.java +++ b/location/java/android/location/RealTimeIntegrityModel.java @@ -26,6 +26,10 @@ import android.os.Parcelable; import com.android.internal.util.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * A class contains the real time integrity status of a GNSS satellite based on notice advisory. * @@ -35,8 +39,7 @@ import com.android.internal.util.Preconditions; @SystemApi public final class RealTimeIntegrityModel implements Parcelable { /** - * Pseudo-random or satellite ID number for the satellite, - * a.k.a. Space Vehicle (SV), or OSN number for Glonass. + * Bad satellite ID number or OSN number for Glonass. * * <p>The distinction is made by looking at the constellation field. Values * must be in the range of: @@ -47,10 +50,14 @@ public final class RealTimeIntegrityModel implements Parcelable { * <p> - Galileo: 1-36 * <p> - Beidou: 1-63 */ - private final int mSvid; + private final int mBadSvid; - /** Indicates whether the satellite is currently usable for navigation. */ - private final boolean mUsable; + /** + * The type of the bad signal or signals. + * + * <p>An empty list means that all signals on the specific SV are not healthy. + */ + @NonNull private final List<GnssSignalType> mBadSignalTypes; /** UTC timestamp (in seconds) when the advisory was published. */ private final long mPublishDateSeconds; @@ -81,14 +88,19 @@ public final class RealTimeIntegrityModel implements Parcelable { private RealTimeIntegrityModel(Builder builder) { // Allow SV ID beyond the range to support potential future extensibility. - Preconditions.checkArgument(builder.mSvid >= 1); + Preconditions.checkArgument(builder.mBadSvid >= 1); Preconditions.checkArgument(builder.mPublishDateSeconds > 0); Preconditions.checkArgument(builder.mStartDateSeconds > 0); Preconditions.checkArgument(builder.mEndDateSeconds > 0); Preconditions.checkNotNull(builder.mAdvisoryType, "AdvisoryType cannot be null"); Preconditions.checkNotNull(builder.mAdvisoryNumber, "AdvisoryNumber cannot be null"); - mSvid = builder.mSvid; - mUsable = builder.mUsable; + if (builder.mBadSignalTypes == null) { + mBadSignalTypes = new ArrayList<>(); + } else { + mBadSignalTypes = Collections.unmodifiableList( + new ArrayList<>(builder.mBadSignalTypes)); + } + mBadSvid = builder.mBadSvid; mPublishDateSeconds = builder.mPublishDateSeconds; mStartDateSeconds = builder.mStartDateSeconds; mEndDateSeconds = builder.mEndDateSeconds; @@ -110,13 +122,18 @@ public final class RealTimeIntegrityModel implements Parcelable { * <p> - Beidou: 1-63 */ @IntRange(from = 1, to = 206) - public int getSvid() { - return mSvid; + public int getBadSvid() { + return mBadSvid; } - /** Returns whether the satellite is usable or not. */ - public boolean isUsable() { - return mUsable; + /** + * Returns the type of the bad signal or signals. + * + * <p>An empty list means that all signals on the specific SV are not healthy. + */ + @NonNull + public List<GnssSignalType> getBadSignalTypes() { + return mBadSignalTypes; } /** Returns the UTC timestamp (in seconds) when the advisory was published */ @@ -156,8 +173,9 @@ public final class RealTimeIntegrityModel implements Parcelable { public RealTimeIntegrityModel createFromParcel(Parcel in) { RealTimeIntegrityModel realTimeIntegrityModel = new RealTimeIntegrityModel.Builder() - .setSvid(in.readInt()) - .setUsable(in.readBoolean()) + .setBadSvid(in.readInt()) + .setBadSignalTypes( + in.createTypedArrayList(GnssSignalType.CREATOR)) .setPublishDateSeconds(in.readLong()) .setStartDateSeconds(in.readLong()) .setEndDateSeconds(in.readLong()) @@ -180,8 +198,8 @@ public final class RealTimeIntegrityModel implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeInt(mSvid); - parcel.writeBoolean(mUsable); + parcel.writeInt(mBadSvid); + parcel.writeTypedList(mBadSignalTypes); parcel.writeLong(mPublishDateSeconds); parcel.writeLong(mStartDateSeconds); parcel.writeLong(mEndDateSeconds); @@ -193,8 +211,8 @@ public final class RealTimeIntegrityModel implements Parcelable { @NonNull public String toString() { StringBuilder builder = new StringBuilder("RealTimeIntegrityModel["); - builder.append("svid = ").append(mSvid); - builder.append(", usable = ").append(mUsable); + builder.append("badSvid = ").append(mBadSvid); + builder.append(", badSignalTypes = ").append(mBadSignalTypes); builder.append(", publishDateSeconds = ").append(mPublishDateSeconds); builder.append(", startDateSeconds = ").append(mStartDateSeconds); builder.append(", endDateSeconds = ").append(mEndDateSeconds); @@ -206,8 +224,8 @@ public final class RealTimeIntegrityModel implements Parcelable { /** Builder for {@link RealTimeIntegrityModel} */ public static final class Builder { - private int mSvid; - private boolean mUsable; + private int mBadSvid; + private List<GnssSignalType> mBadSignalTypes; private long mPublishDateSeconds; private long mStartDateSeconds; private long mEndDateSeconds; @@ -215,8 +233,7 @@ public final class RealTimeIntegrityModel implements Parcelable { private String mAdvisoryNumber; /** - * Sets the Pseudo-random or satellite ID number for the satellite, - * a.k.a. Space Vehicle (SV), or OSN number for Glonass. + * Sets the bad satellite ID number or OSN number for Glonass. * * <p>The distinction is made by looking at the constellation field. Values * must be in the range of: @@ -228,15 +245,19 @@ public final class RealTimeIntegrityModel implements Parcelable { * <p> - Beidou: 1-63 */ @NonNull - public Builder setSvid(@IntRange(from = 1, to = 206) int svid) { - mSvid = svid; + public Builder setBadSvid(@IntRange(from = 1, to = 206) int badSvid) { + mBadSvid = badSvid; return this; } - /** Sets whether the satellite is usable or not. */ + /** + * Sets the type of the bad signal or signals. + * + * <p>An empty list means that all signals on the specific SV are not healthy. + */ @NonNull - public Builder setUsable(boolean usable) { - mUsable = usable; + public Builder setBadSignalTypes(@NonNull List<GnssSignalType> badSignalTypes) { + mBadSignalTypes = badSignalTypes; return this; } diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig index c02cc808d60c..1b38982f48c1 100644 --- a/location/java/android/location/flags/location.aconfig +++ b/location/java/android/location/flags/location.aconfig @@ -167,4 +167,4 @@ flag { namespace: "location" description: "Flag for GNSS assistance interface" bug: "209078566" -}
\ No newline at end of file +} diff --git a/location/java/android/location/provider/GnssAssistanceProviderBase.java b/location/java/android/location/provider/GnssAssistanceProviderBase.java new file mode 100644 index 000000000000..f4b26d5033a5 --- /dev/null +++ b/location/java/android/location/provider/GnssAssistanceProviderBase.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location.provider; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.Context; +import android.content.Intent; +import android.location.GnssAssistance; +import android.location.flags.Flags; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.OutcomeReceiver; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + + +/** + * Base class for GNSS assistance providers outside the system server. + * + * <p>GNSS assistance providers should be wrapped in a non-exported service which returns the result + * of {@link #getBinder()} from the service's {@link android.app.Service#onBind(Intent)} method. The + * service should not be exported so that components other than the system server cannot bind to it. + * Alternatively, the service may be guarded by a permission that only system server can obtain. The + * service may specify metadata on its capabilities: + * + * <ul> + * <li>"serviceVersion": An integer version code to help tie break if multiple services are + * capable of implementing the geocode provider. All else equal, the service with the highest + * version code will be chosen. Assumed to be 0 if not specified. + * <li>"serviceIsMultiuser": A boolean property, indicating if the service wishes to take + * responsibility for handling changes to the current user on the device. If true, the service + * will always be bound from the system user. If false, the service will always be bound from + * the current user. If the current user changes, the old binding will be released, and a new + * binding established under the new user. Assumed to be false if not specified. + * </ul> + * + * <p>The service should have an intent filter in place for the GNSS assistance provider as + * specified by the constant in this class. + * + * <p>GNSS assistance providers are identified by their UID / package name / attribution tag. Based + * on this identity, geocode providers may be given some special privileges. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public abstract class GnssAssistanceProviderBase { + + /** + * The action the wrapping service should have in its intent filter to implement the GNSS + * Assistance provider. + */ + public static final String ACTION_GNSS_ASSISTANCE_PROVIDER = + "android.location.provider.action.GNSS_ASSISTANCE_PROVIDER"; + + final String mTag; + @Nullable + final String mAttributionTag; + final IBinder mBinder; + + /** + * Subclasses should pass in a context and an arbitrary tag that may be used for logcat logging + * of errors, and thus should uniquely identify the class. + */ + public GnssAssistanceProviderBase(@NonNull Context context, @NonNull String tag) { + mTag = tag; + mAttributionTag = context.getAttributionTag(); + mBinder = new GnssAssistanceProviderBase.Service(); + } + + /** + * Returns the IBinder instance that should be returned from the {@link + * android.app.Service#onBind(Intent)} method of the wrapping service. + */ + @NonNull + public final IBinder getBinder() { + return mBinder; + } + + /** + * Requests GNSS assistance data of the given arguments. The given callback must be invoked + * once. + */ + public abstract void onRequest( + @NonNull OutcomeReceiver<GnssAssistance, Throwable> callback); + + private class Service extends IGnssAssistanceProvider.Stub { + @Override + public void request(IGnssAssistanceCallback callback) { + try { + onRequest(new GnssAssistanceProviderBase.SingleUseCallback(callback)); + } catch (RuntimeException e) { + // exceptions on one-way binder threads are dropped - move to a different thread + Log.w(mTag, e); + new Handler(Looper.getMainLooper()) + .post( + () -> { + throw new AssertionError(e); + }); + } + } + } + + private static class SingleUseCallback implements + OutcomeReceiver<GnssAssistance, Throwable> { + + private final AtomicReference<IGnssAssistanceCallback> mCallback; + + SingleUseCallback(IGnssAssistanceCallback callback) { + mCallback = new AtomicReference<>(callback); + } + + @Override + public void onError(Throwable e) { + try { + Objects.requireNonNull(mCallback.getAndSet(null)).onError(); + } catch (RemoteException r) { + throw r.rethrowFromSystemServer(); + } + } + + @Override + public void onResult(GnssAssistance result) { + try { + Objects.requireNonNull(mCallback.getAndSet(null)).onResult(result); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } +} diff --git a/core/tests/coretests/src/android/graphics/GraphicsTests.java b/location/java/android/location/provider/IGnssAssistanceCallback.aidl index 70f5976843bc..ea38d08df6c2 100644 --- a/core/tests/coretests/src/android/graphics/GraphicsTests.java +++ b/location/java/android/location/provider/IGnssAssistanceCallback.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,15 @@ * limitations under the License. */ -package android.graphics; +package android.location.provider; -import junit.framework.TestSuite; +import android.location.GnssAssistance; -public class GraphicsTests { - public static TestSuite suite() { - TestSuite suite = new TestSuite(GraphicsTests.class.getName()); - - suite.addTestSuite(BitmapTest.class); - return suite; - } +/** + * Binder interface for GNSS assistance callbacks. + * @hide + */ +oneway interface IGnssAssistanceCallback { + void onError(); + void onResult(in GnssAssistance result); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherView.java b/location/java/android/location/provider/IGnssAssistanceProvider.aidl index 3f0e23f7c72e..1796e9edb347 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherView.java +++ b/location/java/android/location/provider/IGnssAssistanceProvider.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,15 @@ * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package android.location.provider; -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; +import android.location.provider.IGnssAssistanceCallback; /** - * The container for the user switcher on Keyguard. + * Binder interface for services that implement GNSS assistance providers. Do not implement this + * directly, extend {@link GnssAssistanceProviderBase} instead. + * @hide */ -public class KeyguardUserSwitcherView extends FrameLayout { - - public KeyguardUserSwitcherView(Context context, AttributeSet attrs) { - super(context, attrs); - } +oneway interface IGnssAssistanceProvider { + void request(in IGnssAssistanceCallback callback); } diff --git a/media/java/android/media/FadeManagerConfiguration.java b/media/java/android/media/FadeManagerConfiguration.java index 6d84e7066839..b91a5b57ac6b 100644 --- a/media/java/android/media/FadeManagerConfiguration.java +++ b/media/java/android/media/FadeManagerConfiguration.java @@ -673,6 +673,7 @@ public final class FadeManagerConfiguration implements Parcelable { return config != null ? config.getDuration() : DURATION_NOT_SET; } + @Nullable private VolumeShaper.Configuration getVolumeShaperConfigFromWrapper( FadeVolumeShaperConfigsWrapper wrapper, boolean isFadeIn) { // if no volume shaper config is available, return null diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index 09f40e005b4c..f42017dc835a 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -226,6 +226,10 @@ public abstract class MediaRoute2ProviderService extends Service { @GuardedBy("mSessionLock") private final ArrayMap<String, MediaStreams> mOngoingMediaStreams = new ArrayMap<>(); + @GuardedBy("mSessionLock") + private final ArrayMap<String, RoutingSessionInfo> mPendingSystemSessionReleases = + new ArrayMap<>(); + public MediaRoute2ProviderService() { mHandler = new Handler(Looper.getMainLooper()); } @@ -358,7 +362,9 @@ public abstract class MediaRoute2ProviderService extends Service { * @return a {@link MediaStreams} instance that holds the media streams to route as part of the * newly created routing session. May be null if system media capture failed, in which case * you can ignore the return value, as you will receive a call to {@link #onReleaseSession} - * where you can clean up this session + * where you can clean up this session. {@link AudioRecord#startRecording()} must be called + * immediately on {@link MediaStreams#getAudioRecord()} after calling this method, in order + * to start streaming audio to the receiver. * @hide */ // TODO: b/362507305 - Unhide once the implementation and CTS are in place. @@ -417,7 +423,7 @@ public abstract class MediaRoute2ProviderService extends Service { } AudioFormat audioFormat = formats.mAudioFormat; - var mediaStreamsBuilder = new MediaStreams.Builder(); + var mediaStreamsBuilder = new MediaStreams.Builder(sessionInfo); if (audioFormat != null) { populateAudioStream(audioFormat, uid, mediaStreamsBuilder); } @@ -458,7 +464,6 @@ public abstract class MediaRoute2ProviderService extends Service { if (uid != Process.INVALID_UID) { audioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid); } - AudioMix mix = new AudioMix.Builder(audioMixingRuleBuilder.build()) .setFormat(audioFormat) @@ -471,7 +476,11 @@ public abstract class MediaRoute2ProviderService extends Service { Log.e(TAG, "Couldn't fetch the audio manager."); return; } - audioManager.registerAudioPolicy(audioPolicy); + int audioPolicyResult = audioManager.registerAudioPolicy(audioPolicy); + if (audioPolicyResult != AudioManager.SUCCESS) { + Log.e(TAG, "Failed to register the audio policy."); + return; + } var audioRecord = audioPolicy.createAudioRecordSink(mix); if (audioRecord == null) { Log.e(TAG, "Audio record creation failed."); @@ -521,8 +530,14 @@ public abstract class MediaRoute2ProviderService extends Service { RoutingSessionInfo sessionInfo; synchronized (mSessionLock) { sessionInfo = mSessionInfos.remove(sessionId); - maybeReleaseMediaStreams(sessionId); - + if (Flags.enableMirroringInMediaRouter2()) { + if (sessionInfo == null) { + sessionInfo = maybeReleaseMediaStreams(sessionId); + } + if (sessionInfo == null) { + sessionInfo = mPendingSystemSessionReleases.remove(sessionId); + } + } if (sessionInfo == null) { Log.w(TAG, "notifySessionReleased: Ignoring unknown session info."); return; @@ -539,18 +554,26 @@ public abstract class MediaRoute2ProviderService extends Service { } } - /** Releases any system media routing resources associated with the given {@code sessionId}. */ - private void maybeReleaseMediaStreams(String sessionId) { + /** + * Releases any system media routing resources associated with the given {@code sessionId}. + * + * @return The {@link RoutingSessionInfo} that corresponds to the released media streams, or + * null if no streams were released. + */ + @Nullable + private RoutingSessionInfo maybeReleaseMediaStreams(String sessionId) { if (!Flags.enableMirroringInMediaRouter2()) { - return; + return null; } synchronized (mSessionLock) { var streams = mOngoingMediaStreams.remove(sessionId); if (streams != null) { releaseAudioStream(streams.mAudioPolicy, streams.mAudioRecord); // TODO: b/380431086: Release the video stream once implemented. + return streams.mSessionInfo; } } + return null; } // We cannot reach the code that requires MODIFY_AUDIO_ROUTING without holding it. @@ -1019,12 +1042,16 @@ public abstract class MediaRoute2ProviderService extends Service { if (!checkCallerIsSystem()) { return; } - if (!checkSessionIdIsValid(sessionId, "releaseSession")) { - return; + synchronized (mSessionLock) { + // We proactively release the system media routing session resources when the + // system requests it, to ensure it happens immediately. + RoutingSessionInfo releasedSession = maybeReleaseMediaStreams(sessionId); + if (releasedSession != null) { + mPendingSystemSessionReleases.put(sessionId, releasedSession); + } else if (!checkSessionIdIsValid(sessionId, "releaseSession")) { + return; + } } - // We proactively release the system media routing once the system requests it, to - // ensure it happens immediately. - maybeReleaseMediaStreams(sessionId); addRequestId(requestId); mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession, @@ -1047,9 +1074,19 @@ public abstract class MediaRoute2ProviderService extends Service { @Nullable private final AudioPolicy mAudioPolicy; @Nullable private final AudioRecord mAudioRecord; + /** + * Holds the last {@link RoutingSessionInfo} associated with these streams. + * + * @hide + */ + @GuardedBy("MediaRoute2ProviderService.this.mSessionLock") + @NonNull + private RoutingSessionInfo mSessionInfo; + // TODO: b/380431086: Add the video equivalent. private MediaStreams(Builder builder) { + this.mSessionInfo = builder.mSessionInfo; this.mAudioPolicy = builder.mAudioPolicy; this.mAudioRecord = builder.mAudioRecord; } @@ -1070,9 +1107,19 @@ public abstract class MediaRoute2ProviderService extends Service { */ public static final class Builder { + @NonNull private RoutingSessionInfo mSessionInfo; @Nullable private AudioPolicy mAudioPolicy; @Nullable private AudioRecord mAudioRecord; + /** + * Constructor. + * + * @param sessionInfo The {@link RoutingSessionInfo} associated with these streams. + */ + Builder(@NonNull RoutingSessionInfo sessionInfo) { + mSessionInfo = requireNonNull(sessionInfo); + } + /** Populates system media audio-related structures. */ public Builder setAudioStream( @NonNull AudioPolicy audioPolicy, @NonNull AudioRecord audioRecord) { diff --git a/nfc/tests/src/android/nfc/NfcManagerTest.java b/nfc/tests/src/android/nfc/NfcManagerTest.java new file mode 100644 index 000000000000..06314cc03d37 --- /dev/null +++ b/nfc/tests/src/android/nfc/NfcManagerTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +@RunWith(AndroidJUnit4.class) +public class NfcManagerTest { + + private MockitoSession mMockitoSession; + private NfcManager mNfcManager; + @Mock + private Context mContext; + + @Before + public void setUp() { + mMockitoSession = ExtendedMockito.mockitoSession() + .mockStatic(NfcAdapter.class) + .strictness(Strictness.LENIENT) + .startMocking(); + MockitoAnnotations.initMocks(this); + + when(NfcAdapter.getNfcAdapter(any())).thenReturn(mock(NfcAdapter.class)); + when(mContext.getApplicationContext()).thenReturn(mContext); + mNfcManager = new NfcManager(mContext); + } + + @After + public void tearDown() { + mMockitoSession.finishMocking(); + } + + @Test + public void testGetDefaultAdapter() { + NfcAdapter nfcAdapter = mNfcManager.getDefaultAdapter(); + assertThat(nfcAdapter).isNotNull(); + } +} diff --git a/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java b/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java new file mode 100644 index 000000000000..6be95adbeba0 --- /dev/null +++ b/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.cardemulation; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.nfc.INfcCardEmulation; +import android.nfc.NfcAdapter; +import android.os.RemoteException; +import android.os.UserHandle; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +@RunWith(AndroidJUnit4.class) +public class CardemulationTest { + + private CardEmulation mCardEmulation; + @Mock + private Context mContext; + @Mock + private INfcCardEmulation mINfcCardEmulation; + @Mock + private NfcAdapter mNfcAdapter; + @Mock + private PackageManager mPackageManager; + private MockitoSession mMockitoSession; + + @Before + public void setUp() { + mMockitoSession = ExtendedMockito.mockitoSession() + .mockStatic(NfcAdapter.class) + .strictness(Strictness.LENIENT) + .startMocking(); + MockitoAnnotations.initMocks(this); + + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) + .thenReturn(true); + when(mContext.getApplicationContext()).thenReturn(mContext); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + assertThat(mNfcAdapter).isNotNull(); + when(mNfcAdapter.getCardEmulationService()).thenReturn(mINfcCardEmulation); + when(mNfcAdapter.getContext()).thenReturn(mContext); + mCardEmulation = CardEmulation.getInstance(mNfcAdapter); + } + + @After + public void tearDown() { + mMockitoSession.finishMocking(); + } + + @Test + public void testIsDefaultServiceForCategory() throws RemoteException { + ComponentName componentName = mock(ComponentName.class); + UserHandle userHandle = mock(UserHandle.class); + when(userHandle.getIdentifier()).thenReturn(1); + when(mContext.getUser()).thenReturn(userHandle); + when(mINfcCardEmulation.isDefaultServiceForCategory(1, componentName, + "payment")).thenReturn(true); + boolean result = mCardEmulation.isDefaultServiceForCategory(componentName, + "payment"); + assertThat(result).isTrue(); + verify(mINfcCardEmulation).isDefaultServiceForCategory(1, componentName, + "payment"); + + } + + @Test + public void testIsDefaultServiceForAid() throws RemoteException { + ComponentName componentName = mock(ComponentName.class); + UserHandle userHandle = mock(UserHandle.class); + when(userHandle.getIdentifier()).thenReturn(1); + when(mContext.getUser()).thenReturn(userHandle); + when(mINfcCardEmulation.isDefaultServiceForAid(1, componentName, + "payment")).thenReturn(true); + boolean result = mCardEmulation.isDefaultServiceForAid(componentName, + "payment"); + assertThat(result).isTrue(); + verify(mINfcCardEmulation).isDefaultServiceForAid(1, componentName, + "payment"); + } +} diff --git a/nfc/tests/src/android/nfc/dta/NfcDtaTest.java b/nfc/tests/src/android/nfc/dta/NfcDtaTest.java new file mode 100644 index 000000000000..38fb7ef311b5 --- /dev/null +++ b/nfc/tests/src/android/nfc/dta/NfcDtaTest.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.dta; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.nfc.INfcDta; +import android.nfc.NfcAdapter; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class NfcDtaTest { + private final String mServiceName = "serviceName"; + private final int mServiceSap = 1; + private final int mMiu = 1; + private final int mRwSize = 1; + private final int mTestCaseId = 1; + @Mock + private NfcAdapter mMockNfcAdapter; + @Mock + private INfcDta mMockService; + @Mock + private Context mMockContext; + + private NfcDta mNfcDta; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(mMockNfcAdapter.getContext()).thenReturn(mMockContext); + when(mMockNfcAdapter.getNfcDtaInterface()).thenReturn(mMockService); + + mNfcDta = NfcDta.getInstance(mMockNfcAdapter); + } + + @Test + public void testEnableData() throws RemoteException { + assertTrue(mNfcDta.enableDta()); + verify(mMockService).enableDta(); + } + + @Test + public void testEnableDataWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).enableDta(); + + assertFalse(mNfcDta.enableDta()); + verify(mMockService).enableDta(); + } + + @Test + public void testDisableData() throws RemoteException { + assertTrue(mNfcDta.disableDta()); + verify(mMockService).disableDta(); + } + + @Test + public void testDisableDataWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).disableDta(); + + assertFalse(mNfcDta.disableDta()); + verify(mMockService).disableDta(); + } + + @Test + public void testEnableServer() throws RemoteException { + when(mMockService.enableServer(mServiceName, mServiceSap, mMiu, mRwSize, + mTestCaseId)).thenReturn(true); + + mNfcDta.enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId); + verify(mMockService).enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId); + } + + @Test + public void testEnableServerWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).enableServer(mServiceName, mServiceSap, + mMiu, + mRwSize, mTestCaseId); + + mNfcDta.enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId); + verify(mMockService).enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId); + } + + @Test + public void testDisableServer() throws RemoteException { + assertTrue(mNfcDta.disableServer()); + verify(mMockService).disableServer(); + } + + @Test + public void testDisableServerWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).disableServer(); + + assertFalse(mNfcDta.disableServer()); + verify(mMockService).disableServer(); + } + + @Test + public void testEnableClient() throws RemoteException { + when(mMockService.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId)).thenReturn(true); + + mNfcDta.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId); + verify(mMockService).enableClient(mServiceName, mMiu, mRwSize, mTestCaseId); + } + + @Test + public void testEnableClientWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).enableClient(mServiceName, mMiu, mRwSize, + mTestCaseId); + + mNfcDta.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId); + verify(mMockService).enableClient(mServiceName, mMiu, mRwSize, mTestCaseId); + } + + @Test + public void testDisableClient() throws RemoteException { + assertTrue(mNfcDta.disableClient()); + verify(mMockService).disableClient(); + } + + @Test + public void testDisableClientWithRemoteException() throws RemoteException { + doThrow(new RemoteException()).when(mMockService).disableClient(); + + assertFalse(mNfcDta.disableClient()); + verify(mMockService).disableClient(); + } + + @Test + public void testRegisterMessageService() throws RemoteException { + String msgServiceName = "sampleServiceName"; + when(mMockService.registerMessageService(msgServiceName)).thenReturn(true); + + mNfcDta.registerMessageService(msgServiceName); + verify(mMockService).registerMessageService(msgServiceName); + } + + @Test + public void testRegisterMessageServiceWithRemoteException() throws RemoteException { + String msgServiceName = "sampleServiceName"; + doThrow(new RemoteException()).when(mMockService).registerMessageService(msgServiceName); + + assertFalse(mNfcDta.registerMessageService(msgServiceName)); + } + + @Test(expected = NullPointerException.class) + public void testGetInstanceWithNullPointerException() { + NfcDta.getInstance(null); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetInstanceWithUnsupportedOperationExceptionForNfcAdapterContext() { + when(mMockNfcAdapter.getContext()).thenReturn(null); + + NfcDta.getInstance(mMockNfcAdapter); + } +} diff --git a/nfc/tests/src/android/nfc/tech/NfcATest.java b/nfc/tests/src/android/nfc/tech/NfcATest.java new file mode 100644 index 000000000000..40076ebd0a0a --- /dev/null +++ b/nfc/tests/src/android/nfc/tech/NfcATest.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.tech; + +import static android.nfc.tech.NfcA.EXTRA_ATQA; +import static android.nfc.tech.NfcA.EXTRA_SAK; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.nfc.ErrorCodes; +import android.nfc.INfcTag; +import android.nfc.Tag; +import android.nfc.TransceiveResult; +import android.os.Bundle; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; + +public class NfcATest { + @Mock + private Tag mMockTag; + @Mock + private INfcTag mMockTagService; + @Mock + private Bundle mMockBundle; + private NfcA mNfcA; + private final byte[] mSampleArray = new byte[] {1, 2, 3}; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + when(mMockBundle.getShort(EXTRA_SAK)).thenReturn((short) 1); + when(mMockBundle.getByteArray(EXTRA_ATQA)).thenReturn(mSampleArray); + when(mMockTag.getTechExtras(TagTechnology.NFC_A)).thenReturn(mMockBundle); + + mNfcA = new NfcA(mMockTag); + } + + @Test + public void testGetNfcAWithTech() { + Tag mockTag = mock(Tag.class); + when(mockTag.getTechExtras(TagTechnology.NFC_A)).thenReturn(mMockBundle); + when(mockTag.hasTech(TagTechnology.NFC_A)).thenReturn(true); + + assertNotNull(NfcA.get(mockTag)); + verify(mockTag).getTechExtras(TagTechnology.NFC_A); + verify(mockTag).hasTech(TagTechnology.NFC_A); + } + + @Test + public void testGetNfcAWithoutTech() { + when(mMockTag.hasTech(TagTechnology.NFC_A)).thenReturn(false); + assertNull(NfcA.get(mMockTag)); + } + + @Test + public void testGetAtga() { + assertNotNull(mNfcA.getAtqa()); + } + + @Test + public void testGetSak() { + assertEquals((short) 1, mNfcA.getSak()); + } + + @Test + public void testTransceive() throws IOException, RemoteException { + TransceiveResult mockTransceiveResult = mock(TransceiveResult.class); + when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_A); + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTag.getServiceHandle()).thenReturn(1); + when(mMockTagService.transceive(1, mSampleArray, true)) + .thenReturn(mockTransceiveResult); + when(mockTransceiveResult.getResponseOrThrow()).thenReturn(mSampleArray); + + mNfcA.transceive(mSampleArray); + verify(mMockTag).getTagService(); + verify(mMockTag).getServiceHandle(); + } + + @Test + public void testGetMaxTransceiveLength() throws RemoteException { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_A)).thenReturn(1); + + mNfcA.getMaxTransceiveLength(); + verify(mMockTag).getTagService(); + } + + @Test + public void testSetTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_A, 1000)).thenReturn( + ErrorCodes.SUCCESS); + + mNfcA.setTimeout(1000); + verify(mMockTag).getTagService(); + verify(mMockTagService).setTimeout(TagTechnology.NFC_A, 1000); + } catch (Exception e) { + fail("Unexpected exception during valid setTimeout: " + e.getMessage()); + } + } + + @Test + public void testSetTimeoutInvalidTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_A, -1)).thenReturn( + ErrorCodes.ERROR_TIMEOUT); + + assertThrows(IllegalArgumentException.class, () -> mNfcA.setTimeout(-1)); + } catch (Exception e) { + fail("Unexpected exception during invalid setTimeout: " + e.getMessage()); + } + } + + @Test + public void testSetTimeoutRemoteException() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_A, 1000)).thenThrow( + new RemoteException()); + + mNfcA.setTimeout(1000); // Should not throw an exception but log it + verify(mMockTag).getTagService(); + verify(mMockTagService).setTimeout(TagTechnology.NFC_A, 1000); + } catch (Exception e) { + fail("Unexpected exception during RemoteException in setTimeout: " + e.getMessage()); + } + + } + + @Test + public void testGetTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.getTimeout(TagTechnology.NFC_A)).thenReturn(2000); + + assertEquals(2000, mNfcA.getTimeout()); + verify(mMockTag).getTagService(); + verify(mMockTagService).getTimeout(TagTechnology.NFC_A); + } catch (Exception e) { + fail("Unexpected exception during valid getTimeout: " + e.getMessage()); + } + } + + @Test + public void testGetTimeoutRemoteException() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.getTimeout(TagTechnology.NFC_A)).thenThrow(new RemoteException()); + + assertEquals(0, mNfcA.getTimeout()); + } catch (Exception e) { + fail("Unexpected exception during RemoteException in getTimeout: " + e.getMessage()); + } + } +} diff --git a/nfc/tests/src/android/nfc/tech/NfcBTest.java b/nfc/tests/src/android/nfc/tech/NfcBTest.java new file mode 100644 index 000000000000..98d6070e760c --- /dev/null +++ b/nfc/tests/src/android/nfc/tech/NfcBTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.tech; + +import static android.nfc.tech.NfcB.EXTRA_APPDATA; +import static android.nfc.tech.NfcB.EXTRA_PROTINFO; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.nfc.INfcTag; +import android.nfc.Tag; +import android.nfc.TransceiveResult; +import android.os.Bundle; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; + +public class NfcBTest { + private final byte[] mSampleAppDate = new byte[] {1, 2, 3}; + private final byte[] mSampleProtInfo = new byte[] {3, 2, 1}; + @Mock + private Tag mMockTag; + @Mock + private Bundle mMockBundle; + @Mock + private INfcTag mMockTagService; + private NfcB mNfcB; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + when(mMockBundle.getByteArray(EXTRA_APPDATA)).thenReturn(mSampleAppDate); + when(mMockBundle.getByteArray(EXTRA_PROTINFO)).thenReturn(mSampleProtInfo); + when(mMockTag.getTechExtras(TagTechnology.NFC_B)).thenReturn(mMockBundle); + + mNfcB = new NfcB(mMockTag); + } + + @Test + public void testGetApplicationData() { + assertNotNull(mNfcB.getApplicationData()); + } + + @Test + public void testGetProtocolInfo() { + assertNotNull(mNfcB.getProtocolInfo()); + } + + @Test + public void testGetNfcBInstance() { + Tag tag = mock(Tag.class); + when(tag.hasTech(TagTechnology.NFC_B)).thenReturn(true); + when(tag.getTechExtras(TagTechnology.NFC_B)).thenReturn(mMockBundle); + + assertNotNull(NfcB.get(tag)); + verify(tag).hasTech(TagTechnology.NFC_B); + verify(tag).getTechExtras(TagTechnology.NFC_B); + } + + @Test + public void testGetNfcBNullInstance() { + Tag tag = mock(Tag.class); + when(tag.hasTech(TagTechnology.NFC_B)).thenReturn(false); + + assertNull(NfcB.get(tag)); + verify(tag).hasTech(TagTechnology.NFC_B); + verify(tag, never()).getTechExtras(TagTechnology.NFC_B); + } + + + @Test + public void testTransceive() throws IOException, RemoteException { + byte[] sampleData = new byte[] {1, 2, 3, 4, 5}; + TransceiveResult mockTransceiveResult = mock(TransceiveResult.class); + when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_B); + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTag.getServiceHandle()).thenReturn(1); + when(mMockTagService.transceive(1, sampleData, true)) + .thenReturn(mockTransceiveResult); + when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData); + + mNfcB.transceive(sampleData); + verify(mMockTag).getTagService(); + verify(mMockTag).getServiceHandle(); + } + + @Test + public void testGetMaxTransceiveLength() throws RemoteException { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_B)).thenReturn(1); + + mNfcB.getMaxTransceiveLength(); + verify(mMockTag).getTagService(); + } +} diff --git a/nfc/tests/src/android/nfc/tech/NfcFTest.java b/nfc/tests/src/android/nfc/tech/NfcFTest.java new file mode 100644 index 000000000000..31a6943566e0 --- /dev/null +++ b/nfc/tests/src/android/nfc/tech/NfcFTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc.tech; + +import static android.nfc.tech.NfcF.EXTRA_PMM; +import static android.nfc.tech.NfcF.EXTRA_SC; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.nfc.ErrorCodes; +import android.nfc.INfcTag; +import android.nfc.Tag; +import android.nfc.TransceiveResult; +import android.os.Bundle; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; + +public class NfcFTest { + private final byte[] mSampleSystemCode = new byte[] {1, 2, 3}; + private final byte[] mSampleManufacturer = new byte[] {3, 2, 1}; + @Mock + private Tag mMockTag; + @Mock + private INfcTag mMockTagService; + @Mock + private Bundle mMockBundle; + private NfcF mNfcF; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + when(mMockBundle.getByteArray(EXTRA_SC)).thenReturn(mSampleSystemCode); + when(mMockBundle.getByteArray(EXTRA_PMM)).thenReturn(mSampleManufacturer); + when(mMockTag.getTechExtras(TagTechnology.NFC_F)).thenReturn(mMockBundle); + + mNfcF = new NfcF(mMockTag); + } + + @Test + public void testGetSystemCode() { + assertNotNull(mNfcF.getSystemCode()); + } + + @Test + public void testGetManufacturer() { + assertNotNull(mNfcF.getManufacturer()); + } + + @Test + public void testGetNfcFInstanceWithTech() { + Tag tag = mock(Tag.class); + when(tag.getTechExtras(TagTechnology.NFC_F)).thenReturn(mMockBundle); + when(tag.hasTech(TagTechnology.NFC_F)).thenReturn(true); + + assertNotNull(NfcF.get(tag)); + verify(tag).getTechExtras(TagTechnology.NFC_F); + verify(tag).hasTech(TagTechnology.NFC_F); + } + + @Test + public void testGetNfcFInstanceWithoutTech() { + Tag tag = mock(Tag.class); + when(tag.hasTech(TagTechnology.NFC_F)).thenReturn(false); + + assertNull(NfcF.get(tag)); + verify(tag).hasTech(TagTechnology.NFC_F); + verify(tag, never()).getTechExtras(TagTechnology.NFC_F); + } + + @Test + public void testTransceive() throws IOException, RemoteException { + byte[] sampleData = new byte[]{1, 2, 3, 4, 5}; + TransceiveResult mockTransceiveResult = mock(TransceiveResult.class); + when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_F); + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTag.getServiceHandle()).thenReturn(1); + when(mMockTagService.transceive(1, sampleData, true)) + .thenReturn(mockTransceiveResult); + when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData); + + mNfcF.transceive(sampleData); + verify(mMockTag).getTagService(); + verify(mMockTag).getServiceHandle(); + } + + @Test + public void testGetMaxTransceiveLength() throws RemoteException { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_F)).thenReturn(1); + + mNfcF.getMaxTransceiveLength(); + verify(mMockTag).getTagService(); + } + + @Test + public void testGetTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.getTimeout(TagTechnology.NFC_F)).thenReturn(2000); + + assertEquals(2000, mNfcF.getTimeout()); + verify(mMockTag).getTagService(); + verify(mMockTagService).getTimeout(TagTechnology.NFC_F); + } catch (Exception e) { + fail("Unexpected exception during valid getTimeout: " + e.getMessage()); + } + } + + @Test + public void testGetTimeoutRemoteException() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.getTimeout(TagTechnology.NFC_F)).thenThrow(new RemoteException()); + + assertEquals(0, mNfcF.getTimeout()); + } catch (Exception e) { + fail("Unexpected exception during RemoteException in getTimeout: " + e.getMessage()); + } + } + + @Test + public void testSetTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_F, 1000)).thenReturn( + ErrorCodes.SUCCESS); + + mNfcF.setTimeout(1000); + verify(mMockTag).getTagService(); + verify(mMockTagService).setTimeout(TagTechnology.NFC_F, 1000); + } catch (Exception e) { + fail("Unexpected exception during valid setTimeout: " + e.getMessage()); + } + } + + @Test + public void testSetTimeoutInvalidTimeout() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_F, -1)).thenReturn( + ErrorCodes.ERROR_TIMEOUT); + + assertThrows(IllegalArgumentException.class, () -> mNfcF.setTimeout(-1)); + } catch (Exception e) { + fail("Unexpected exception during invalid setTimeout: " + e.getMessage()); + } + } + + @Test + public void testSetTimeoutRemoteException() { + when(mMockTag.getTagService()).thenReturn(mMockTagService); + try { + when(mMockTagService.setTimeout(TagTechnology.NFC_F, 1000)).thenThrow( + new RemoteException()); + + mNfcF.setTimeout(1000); + verify(mMockTag).getTagService(); + verify(mMockTagService).setTimeout(TagTechnology.NFC_F, 1000); + } catch (Exception e) { + fail("Unexpected exception during RemoteException in setTimeout: " + e.getMessage()); + } + } +} diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index 2a8f17b3d379..ba02bf696407 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestemming om jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> se apps na <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong&gt te stroom?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat sigbaar is of gespeel word op <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, insluitend oudio, foto’s, wagwoorde en boodskappe.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sal apps na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> kan stroom totdat jy toegang tot hierdie toestemming verwyder."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps vanaf jou <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> te stroom"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om oudio- en stelselkenmerke te stroom tussen jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> en <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sal toegang hê tot enigiets wat op jou <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> gespeel word.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sal oudio kan stroom na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> totdat jy toegang tot hierdie toestemming verwyder."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek toestemming namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> om oudio- en stelselkenmerke tussen jou toestelle te stroom."</string> <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string> <string name="summary_generic" msgid="1761976003668044801">"Hierdie app sal inligting kan sinkroniseer, soos die naam van iemand wat bel, tussen jou foon en die gekose toestel"</string> <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index b66860eb5a42..a6b78cb6dcb7 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> መተግበሪያዎች ወደ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>? በዥረት እንዲለቅ ይፍቀዱ"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ኦዲዮ፣ ፎቶዎች፣ የክፍያ መረጃ፣ የይለፍ ቃላት እና መልዕክቶችን ጨምሮ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ላይ የሚታየውን ወይም የሚጫወተውን የማንኛውም ነገር መዳረሻ ይኖረዋል።<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> የዚህን መዳረሻ እስኪያስወግዱ ድረስ መተግበሪያዎችን ወደ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> መተግበሪያዎችን ከእርስዎ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> በዥረት ለመልቀቅ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ን በመወከል ፈቃድ እየጠየቀ ነው"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የኦዲዮ እና የሥርዓት ባህሪያትን በእርስዎ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> እና <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> መካከል በዥረት እንዲለቅ ይፈቀድለት?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> በእርስዎ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ላይ ለሚጫወተው ማንኛውንም ነገር መዳረሻ ይኖረዋል።<br/><br/>እርስዎ የዚህን ፈቃድ መዳረሻ እስኪያስወግዱ ድረስ <xliff:g id="APP_NAME_2">%1$s</xliff:g> አዲዮን ወደ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> በዥረት መልቀቅ ይችላል።"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ን በመወከል በመሣሪያዎችዎ መካከል ኦዲዮን እና የሥርዓት ባህሪያትን በዥረት ለመልቀቅ ፈቃድ እየጠየቀ ነው።"</string> <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string> <string name="summary_generic" msgid="1761976003668044801">"ይህ መተግበሪያ እንደ የሚደውል ሰው ስም ያለ መረጃን በስልክዎ እና በተመረጠው መሣሪያ መካከል ማስመር ይችላል"</string> <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 6f17676bec03..db0704fdb19a 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -36,6 +36,12 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"هل تريد السماح لـ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ببث التطبيقات من <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> إلى <xliff:g id="DEVICE_NAME">%3$s</xliff:g>؟"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"سيتمكّن \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.<br/><br/>سيتمكّن \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" من بثّ التطبيقات إلى <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> إلى أن توقِف إمكانية استخدام هذا الإذن."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DEVICE_NAME">%2$s</xliff:g> لبثّ التطبيقات من <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <!-- no translation found for title_sensor_device_streaming (2395553261097861497) --> + <skip /> + <!-- no translation found for summary_sensor_device_streaming (3413105061195145547) --> + <skip /> + <!-- no translation found for helper_summary_sensor_device_streaming (8860174545653786353) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string> <string name="summary_generic" msgid="1761976003668044801">"سيتمكّن هذا التطبيق من مزامنة المعلومات، مثل اسم المتصل، بين هاتفك والجهاز المحدّد."</string> <string name="consent_yes" msgid="8344487259618762872">"السماح"</string> diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml index 8b001d18643b..c07602afc050 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ এপ্সমূহ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ত ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>এ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ত দৃশ্যমান হোৱা বা প্লে’ কৰা অডিঅ’, ফট’ পাছৱৰ্ড আৰু বাৰ্তাকে ধৰি যিকোনো বস্তু এক্সেছ কৰিব পাৰিব।<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g>এ আপুনি এই অনুমতিৰ এক্সেছ আঁতৰাই নিদিয়া পৰ্যন্ত <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ত এপ্সমূহ ষ্ট্ৰীম কৰিব পাৰিব।"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ আপোনাৰ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ৰ পৰা এপ্সমূহ ষ্ট্ৰীম কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> আৰু <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ৰ মাজত অডিঅ’ আৰু ছিষ্টেমৰ সুবিধাসমূহ ষ্ট্ৰীম কৰিবলৈ দিবনে?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"আপোনাৰ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ত প্লে’ কৰা হোৱা আটাইবোৰ সমল <xliff:g id="APP_NAME_0">%1$s</xliff:g>এ এক্সেছ কৰিব পাৰিব।<br/><br/>আপুনি এই অনুমতিটোৰ এক্সেছ আঁতৰাই নেপেলোৱালৈকে <xliff:g id="APP_NAME_2">%1$s</xliff:g>এ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ত অডিঅ’ ষ্ট্ৰীম কৰিব পাৰিব।"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ ডিভাইচসমূহৰ মাজত অডিঅ’ আৰু ছিষ্টেমৰ সুবিধাসমূহ ষ্ট্ৰীম কৰিবলৈ <xliff:g id="DEVICE_NAME">%2$s</xliff:g>ৰ হৈ অনুমতি বিচাৰি অনুৰোধ জনাইছে।"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string> <string name="summary_generic" msgid="1761976003668044801">"এই এপ্টোৱে আপোনাৰ ফ’ন আৰু বাছনি কৰা ডিভাইচটোৰ মাজত কল কৰোঁতাৰ নামৰ দৰে তথ্য ছিংক কৰিব পাৰিব"</string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index b4fdcecd6d05..f053aa85a28f 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazının tətbiqlərini <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> cihazına yayımlamaq üçün <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə icazə verilsin?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> audio, foto, ödəniş məlumatı, parol və mesajlar daxil olmaqla <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> cihazında görünən və ya oxudulan kontentə giriş əldə edəcək.<br/><br/>Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_2">%1$s</xliff:g> tətbiqləri <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cihazında yayımlaya biləcək."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> cihazından tətbiqləri yayımlamaq üçün <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinin audio və sistem funksiyalarını <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> və <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>? cihazınız arasında yayımlamağına icazə verin"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> cihazınızda oxudulan istənilən kontentə daxil ola biləcək.<br/><br/>Siz bu icazəyə girişi silənə qədər <xliff:g id="APP_NAME_2">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cihazına audio yayımlaya biləcək."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi audio və sistem funksiyalarını cihazlarınız arasında yayımlamaq üçün <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adından icazə tələb edir."</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="summary_generic" msgid="1761976003668044801">"Tətbiq zəng edənin adı kimi məlumatları telefon ilə seçilmiş cihaz arasında sinxronlaşdıracaq"</string> <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index ef97da99afaa..621ea2102747 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Želite da dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strimuje aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se vidi ili pušta na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, uključujući zvuk, slike, informacije o plaćanju, lozinke i poruke.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći da strimuje aplikacije na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje aplikacije sa uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Želite da dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strimuje zvuk i sistemske funkcije između uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> i <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se pušta na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći da strimuje zvuk na <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovoj dozvoli."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> traži dozvolu u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da strimuje zvuk i sistemske funkcije između uređaja."</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći da sinhronizuje podatke, poput imena osobe koja upućuje poziv, između telefona i odabranog uređaja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index c0aaac9c4e38..0cdebcdbeffe 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> трансліраваць праграмы прылады тыпу \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на прыладу <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будзе мець доступ да ўсяго, што паказваецца ці прайграецца на прыладзе \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\", у тым ліку да аўдыя, фота, плацежнай інфармацыі, пароляў і паведамленняў.<br/><br/>Праграма \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" зможа трансліраваць праграмы на прыладу \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на трансляцыю праграм з прылады тыпу \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> трансліраваць аўдыя і сістэмныя функцыі паміж прыладамі \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" і <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> будзе мець доступ да ўсяго, што прайграецца на прыладзе \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\".<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> зможа трансліраваць аўдыя на прыладу \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пакуль вы не адклічаце гэты дазвол."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> запытвае дазвол ад імя прылады \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" на трансляцыю аўдыя і сістэмных функцый паміж прыладамі."</string> <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string> <string name="summary_generic" msgid="1761976003668044801">"Гэта праграма зможа сінхранізаваць інфармацыю (напрыклад, імя таго, хто звоніць) паміж тэлефонам і выбранай прыладай"</string> <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 0fa98ef836ab..f522ab4807ae 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Да се разреши ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предава поточно към <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> приложенията на устройството ви от тип <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се показва или възпроизвежда на устройството ви <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, включително аудио, снимки, пароли и съобщения.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ще може да предава поточно приложения към устройството ви <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, докато не премахнете това разрешение."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно приложения от устройството ви от тип <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Да се разреши ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предава поточно аудио и системни функции между устройството ви <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> и <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ще има достъп до всичко, което се възпроизвежда на устройството ви <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ще може да предава поточно аудио на устройството ви <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, докато не премахнете това разрешение."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да предава поточно аудио и системни функции между устройствата ви."</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="summary_generic" msgid="1761976003668044801">"Това приложение ще може да синхронизира различна информация, като например името на обаждащия се, между телефона ви и избраното устройство"</string> <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index 032eedbf0614..61ec8c9bdf28 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর অ্যাপ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?-এ স্ট্রিম করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-কে অনুমতি দেবেন?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"অডিও, ফটো, পাসওয়ার্ড ও মেসেজ সহ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-এ দেখা ও চালানো যায় এমন সব কিছু <xliff:g id="APP_NAME_0">%1$s</xliff:g> অ্যাক্সেস করতে পারবে।<br/><br/>আপনি এই অনুমতি না সরানো পর্যন্ত <xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-এ অ্যাপ স্ট্রিম করতে পারবে।"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"আপনার <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> থেকে অ্যাপ স্ট্রিম করার জন্য <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চাইছে"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-কে অনুমতি দিন যাতে আপনার <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ও <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?-এর মধ্যে অডিও ও সিস্টেমের ফিচার স্ট্রিম করতে পারে"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"আপনার <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-এ চালানো যায় এমন সব কিছু <xliff:g id="APP_NAME_0">%1$s</xliff:g> অ্যাক্সেস করতে পারবে। <br/><br/>আপনি এই অনুমতি সম্পর্কিত অ্যাক্সেস সরিয়ে না দেওয়া পর্যন্ত<xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-এ অডিও স্ট্রিম করতে পারবে।"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"আপনার বিভিন্ন ডিভাইসের মধ্যে অডিও ও সিস্টেমের ফিচার স্ট্রিম করার জন্য, <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-এর হয়ে <xliff:g id="APP_NAME">%1$s</xliff:g> অনুমতি চাইছে।"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string> <string name="summary_generic" msgid="1761976003668044801">"এই অ্যাপ, আপনার ফোন এবং বেছে নেওয়া ডিভাইসের মধ্যে তথ্য সিঙ্ক করতে পারবে, যেমন কোনও কলারের নাম"</string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 183bdc8a86c8..00205f257315 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da prenosi aplikacije koje sadržava vaš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaju <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> reproducira ili je vidljivo na njemu, uključujući zvukove, fotografije, podatke o plaćanju, lozinke i poruke.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći prenositi aplikacije na uređaju <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prenosi aplikacije s uređaja vrste \"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>\""</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da prenosi zvuk i funkcije sistema između uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> i <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> će imati pristup svemu što se reproducira na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> će moći prenositi zvuk na uređaju <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup ovom odobrenju."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> traži odobrenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> da prenosi zvuk i funkcije sistema između uređaja."</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="1761976003668044801">"Ova aplikacija će moći sinhronizirati informacije, kao što je ime osobe koja upućuje poziv, između vašeg telefona i odabranog uređaja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index 0dc7001fde70..662e297ae00c 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vols permetre que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> reprodueixi en continu les aplicacions del dispositiu (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) a <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> podrà accedir a qualsevol cosa que sigui visible o que es reprodueixi al dispositiu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inclosos àudios, fotos, informació de pagament, contrasenyes i missatges.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrà reproduir en continu aplicacions al dispositiu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> fins que suprimeixis l\'accés a aquest permís."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per reproduir en continu aplicacions del teu dispositiu (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Vols permetre que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> reprodueixi en continu àudio i funcions del sistema entre el dispositiu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> i <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> podrà accedir a qualsevol cosa que es reprodueixi al teu dispositiu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrà reproduir en continu àudio al dispositiu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> fins que suprimeixis l\'accés a aquest permís."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del dispositiu <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per reproduir en continu àudio i funcions del sistema entre els teus dispositius."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string> <string name="summary_generic" msgid="1761976003668044801">"Aquesta aplicació podrà sincronitzar informació, com ara el nom d\'algú que truca, entre el teu telèfon i el dispositiu triat"</string> <string name="consent_yes" msgid="8344487259618762872">"Permet"</string> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index b08081b4840d..6b110d3ae7b1 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovat aplikace na zařízení typu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zařízení <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co na zařízení typu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> zobrazíte nebo přehrajete, včetně zvuku, fotek, platebních údajů, hesel a zpráv.<br/><br/>Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> bude moct streamovat aplikace do zařízení typu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace z vašeho zařízení typu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovat zvuk a systémové funkce mezi zařízeními <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mít přístup ke všemu, co se na zařízení <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> bude přehrávat.<br/><br/>Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> bude moct streamovat zvuk do zařízení typu <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dokud přístup k tomuto oprávnění neodeberete."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> oprávnění ke streamování zvuku a systémových funkcí mezi vašimi zařízeními."</string> <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string> <string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zařízením"</string> <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index da3b26166692..bbd01105c538 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at streame apps fra din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der er synligt eller afspilles på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, herunder lyd, billeder, betalingsoplysninger, adgangskoder og beskeder.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streame apps til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame apps fra din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at streame lyd og systemfunktioner mellem <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> og <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får adgang til alt, der afspilles på din <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streame lyd til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, indtil du fjerner adgangen til denne tilladelse."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til at streame lyd og systemfunktioner mellem dine enheder."</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string> <string name="summary_generic" msgid="1761976003668044801">"Denne app vil kunne synkronisere oplysninger som f.eks. navnet på en person, der ringer, mellem din telefon og den valgte enhed"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index c39145e5f7fc..3eecfe71f6b6 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, die Apps auf deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) auf <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> zu streamen?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hat dann Zugriff auf alle Inhalte, die auf deinem Gerät (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>) sichtbar sind oder abgespielt werden, einschließlich Audioinhalten, Fotos, Zahlungsinformationen, Passwörtern und Nachrichten.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kann so lange Apps auf „<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>“ streamen, bis du diese Berechtigung entfernst."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein Gerät <xliff:g id="DEVICE_NAME">%2$s</xliff:g> um die Berechtigung, Apps von deinem Gerät (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) zu streamen"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Der App <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, Audio und Systemfunktionen zwischen deinem Gerät (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) und <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> zu streamen?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Die App „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ hat dann Zugriff auf alle Inhalte, die auf deinem Gerät (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>) abgespielt werden.<br/><br/>Die App „<xliff:g id="APP_NAME_2">%1$s</xliff:g>“ kann so lange Audioinhalte auf „<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>“ streamen, bis du diese Berechtigung entfernst."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Die App „<xliff:g id="APP_NAME">%1$s</xliff:g>“ bittet für das Gerät (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) um die Berechtigung, Audio und Systemfunktionen zwischen deinen Geräten zu streamen."</string> <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string> <string name="summary_generic" msgid="1761976003668044801">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und dem ausgewählten Gerät synchronisieren"</string> <string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index e465a3876308..a26162f4e077 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Να επιτρέπεται στο <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η δυνατότητα ροής εφαρμογών του <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> σας στο <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>;"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Το <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στο <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, συμπεριλαμβανομένων ήχων, φωτογραφιών, στοιχείων πληρωμής, κωδικών πρόσβασης και μηνυμάτων.<br/><br/>Το <xliff:g id="APP_NAME_2">%1$s</xliff:g> θα έχει τη δυνατότητα ροής εφαρμογών στο <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Το <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους του <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για τη ροή εφαρμογών από το <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> σας"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η μετάδοση σε ροή ήχου και λειτουργιών συστήματος μεταξύ της συσκευής <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> και της συσκευής <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>;"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> θα έχει πρόσβαση σε οτιδήποτε αναπαράγεται στη συσκευή <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>Η εφαρμογή <xliff:g id="APP_NAME_2">%1$s</xliff:g> θα έχει τη δυνατότητα μετάδοσης σε ροή ήχου στη συσκευή <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, μέχρι να καταργήσετε την πρόσβαση σε αυτή την άδεια."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για τη μετάδοση σε ροή ήχου και λειτουργιών συστήματος μεταξύ των συσκευών σας."</string> <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string> <string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της επιλεγμένης συσκευής σας, όπως το όνομα ενός ατόμου που σας καλεί."</string> <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string> diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml index 92f0a1b3b93d..b5fea9f22c15 100644 --- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream audio and system features between your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> and <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s played on your <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream audio to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream audio and system features between your devices."</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index c40018ffe862..42c6b888cddc 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>’s apps to <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords, and messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream audio and system features between your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> and <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that’s played on your <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream audio to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream audio and system features between your devices."</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml index 92f0a1b3b93d..b5fea9f22c15 100644 --- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream audio and system features between your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> and <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s played on your <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream audio to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream audio and system features between your devices."</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml index 92f0a1b3b93d..b5fea9f22c15 100644 --- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\'s apps to <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s visible or played on <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, including audio, photos, payment info, passwords and messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream apps to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream apps from your <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to stream audio and system features between your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> and <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> will have access to anything that\'s played on your <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> will be able to stream audio to <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> until you remove access to this permission."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of <xliff:g id="DEVICE_NAME">%2$s</xliff:g> to stream audio and system features between your devices."</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="1761976003668044801">"This app will be able to sync info, like the name of someone calling, between your phone and the chosen device"</string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index a7a408628690..a5d00a3186e0 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> transmita las apps de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo el contenido visible o que se reproduzca en <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, lo que incluye audio, fotos, información de pago, contraseñas y mensajes.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrá transmitir apps a <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hasta que se quite el acceso a este permiso."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir apps desde tu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"¿Quieres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> transmita audio y funciones del sistema entre tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> y <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo el contenido que se reproduzca en tu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrá transmitir audio a <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hasta que se quite el acceso a este permiso."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para transmitir audio y funciones del sistema entre dispositivos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"Esta app podrá sincronizar información, como el nombre de la persona que llama, entre el teléfono y el dispositivo elegido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 8816e6d48eaa..fc6e6c55557a 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita las aplicaciones de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> en <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo lo que se vea o se reproduzca en <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluidos audio, fotos, información para pagos, contraseñas y mensajes.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrá emitir aplicaciones en <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hasta que quites el acceso a este permiso."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir aplicaciones desde tu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita audio y funciones del sistema entre tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> y tu <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tendrá acceso a todo lo que se reproduzca en tu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> podrá emitir audio en <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hasta que quites el acceso a este permiso."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para emitir audio y funciones del sistema en otros dispositivos tuyos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación podrá sincronizar información (por ejemplo, el nombre de la persona que te llama) entre tu teléfono y el dispositivo que elijas"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index 8099537f41ac..2cbb44134d31 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Kas lubada rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> teie seadme <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> rakendusi seadmesse <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> voogesitada?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie seadmes <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> saab kuvada või esitada, sh helile, fotodele, makseteabele, paroolidele ja sõnumitele.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> saab rakendusi seadmesse <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> voogesitada seni, kuni juurdepääsu sellele loale eemaldate."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba rakenduste voogesitamiseks teie seadmest <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Kas lubada rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> teie seadmete <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ja <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> vahel heli ja süsteemifunktsioone edastada?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Rakendus <xliff:g id="APP_NAME_0">%1$s</xliff:g> saab juurdepääsu kõigele, mida teie seadmes <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> esitatakse.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> saab edastada heli seadmesse <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, kuni selle loa eemaldate."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel heli ja süsteemifunktsioonide edastamiseks."</string> <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string> <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string> <string name="consent_yes" msgid="8344487259618762872">"Luba"</string> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index dd9b47c21f79..3a49cf94ca6b 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuko aplikazioak <xliff:g id="DEVICE_NAME">%3$s</xliff:g> gailura zuzenean igortzeko baimena eman nahi diozu?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> gailuan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> gailura aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> gailutik aplikazioak zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Zure <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> eta <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> gailuen artean audioa eta sistemaren eginbideak zuzenean igortzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> gailuan erreproduzitzen den eduki guztia atzitu ahal izango du.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> gailura audioa zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Gailuen artean audioa eta sistemaren eginbideak zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean."</string> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> <string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string> <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index 7b013bff0016..481522500140 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهید برنامههای <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> را در <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> جاریسازی کند؟"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> به هرچیزی که در <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> شما نمایان است یا پخش میشود، ازجمله صداها، عکسها، اطلاعات پرداخت، گذرواژهها، و پیامها دسترسی خواهد داشت.<br/><br/>تا زمانیکه دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_2">%1$s</xliff:g> میتواند برنامهها را در <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> جاریسازی کند."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه میخواهد برنامهها را از <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> شما جاریسازی کند"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهید صدا و ویژگیهای سیستم را بین <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> و <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> جاریسازی کند؟"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"«<xliff:g id="APP_NAME_0">%1$s</xliff:g>» به هرچیزی که در <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> پخش میشود دسترسی خواهد داشت.<br/><br/>تا زمانیکه دسترسی به این اجازه را حذف نکنید، <xliff:g id="APP_NAME_2">%1$s</xliff:g> میتواند صدا در <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> جاریسازی کند."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» ازطرف <xliff:g id="DEVICE_NAME">%2$s</xliff:g> اجازه میخواهد صدا و ویژگیهای سیستم را بین دستگاههای شما جاریسازی کند."</string> <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string> <string name="summary_generic" msgid="1761976003668044801">"این برنامه مجاز میشود اطلاعتی مثل نام شخصی را که تماس میگیرد بین تلفن شما و دستگاه انتخابشده همگامسازی کند"</string> <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index f20b71b63c47..6e13d6cf542e 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Saako <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> striimata <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> olevia sovelluksia laitteelle (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> näkyvään tai pelattavaan sisältöön, mukaan lukien audioon, kuviin, salasanoihin ja viesteihin.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> voi striimata sovelluksia laitteelle (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>), kunnes poistat luvan."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää lapsen (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteeltasi (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Saako <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> striimata audiota ja järjestelmän ominaisuuksia laitteiden <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ja <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> välillä?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saa pääsyn kaikkeen, mitä <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> toistaa.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> voi striimata audiota laitteelle (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>), kunnes poistat luvan."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteen (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) puolesta lupaa striimata audiota ja järjestelmän ominaisuuksia laitteiden välillä."</string> <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string> <string name="summary_generic" msgid="1761976003668044801">"Sovellus voi synkronoida tietoja (esimerkiksi soittajan nimen) puhelimesi ja valitun laitteen välillä"</string> <string name="consent_yes" msgid="8344487259618762872">"Salli"</string> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index c4a8447d2aed..73a180b586d3 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à diffuser les applis de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> vers <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, y compris le contenu audio, les photos, les infos de paiement, les mots de passe et les messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> pourra diffuser des applis vers <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des applis à partir de votre <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à diffuser des fonctionnalités audio et système entre votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> et votre <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est lu sur votre <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> pourra diffuser de l\'audio sur le <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> jusqu\'à ce que vous retiriez l\'accès à cette autorisation."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des fonctionnalités audio et système entre vos appareils."</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des informations, comme le nom de l\'appelant, entre votre téléphone et l\'appareil sélectionné"</string> <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string> diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index 88627e580e1e..0c0ae7912dc4 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à caster les applis de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sur <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est visible ou lu sur votre <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, y compris les contenus audio, les photos, les infos de paiement, les mots de passe et les messages.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> pourra caster des applis sur <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande, au nom de l\'appareil <xliff:g id="DEVICE_NAME">%2$s</xliff:g>, l\'autorisation de caster des applis depuis votre <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à caster des applis et des fonctionnalités système entre votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> et <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> aura accès à tout ce qui est lu sur votre <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> pourra caster des contenus audio sur <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> jusqu\'à ce que vous supprimiez cette autorisation."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation pour <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de caster des fonctionnalités audio et système d\'un appareil à l\'autre."</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="summary_generic" msgid="1761976003668044801">"Cette appli pourra synchroniser des infos, comme le nom de l\'appelant, entre votre téléphone et l\'appareil choisi"</string> <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index a2bd0f8e449f..71eb86ff32f3 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita as aplicacións do dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) en <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no teu dispositivo (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>), como audio, fotos, información de pago, contrasinais e mensaxes.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá emitir aplicacións en <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ata que quites o acceso a este permiso."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome dun dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir aplicacións do seguinte aparello: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita audio e funcións do sistema entre o teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) e outro aparello <strong>(<xliff:g id="DEVICE_NAME">%3$s</xliff:g>)</strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acceso a todo o que se vexa ou reproduza no dispositivo (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>).<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá emitir audio no dispositivo (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>) ata que quites o acceso a este permiso."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita permiso en nome dun dispositivo (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) para emitir audio e funcións do sistema entre os teus aparellos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"Esta aplicación poderá sincronizar información (por exemplo, o nome de quen chama) entre o teléfono e o dispositivo escollido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index c18ebc0b6559..9b20886bc0af 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"શું <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ની ઍપને <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> પર સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ની પાસે એવી બધી બાબતોનો ઍક્સેસ રહેશે જે <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> પર જોઈ શકાતી કે ચલાવી શકાતી હોય, જેમાં ઑડિયો, ફોટા, ચુકવણીની માહિતી, પાસવર્ડ અને મેસેજ શામેલ છે.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ત્યાં સુધી ઍપને <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> પર સ્ટ્રીમ કરી શકશે, જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢી નહીં નાખો."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>માંથી ઍપ સ્ટ્રીમ કરવા માટે <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> અને <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> વચ્ચે ઑડિયો અને સિસ્ટમની સુવિધાઓ સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"તમારા <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> પર જે કંઈપણ ચલાવવામાં આવે, તેનો ઍક્સેસ <xliff:g id="APP_NAME_0">%1$s</xliff:g> પાસે રહેશે.<br/><br/>જ્યાં સુધી તમે આ પરવાનગીનો ઍક્સેસ કાઢો નહીં, ત્યાં સુધી <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> પર ઑડિયો સ્ટ્રીમ કરી શકશે."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"તમારા ડિવાઇસ વચ્ચે ઑડિયો અને સિસ્ટમની અન્ય સુવિધાઓ સ્ટ્રીમ કરવા માટે, <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> વતી પરવાનગીની વિનંતી કરી રહી છે."</string> <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string> <string name="summary_generic" msgid="1761976003668044801">"આ ઍપ તમારા ફોન અને પસંદ કરેલા ડિવાઇસ વચ્ચે, કૉલ કરનાર કોઈ વ્યક્તિનું નામ જેવી માહિતી સિંક કરી શકશે"</string> <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index 562f7625ce8c..f4a95a462861 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -36,6 +36,12 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"क्या <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> में मौजूद ऐप्लिकेशन को <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> पर स्ट्रीम करने की अनुमति देनी है?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> के पास ऐसे किसी भी कॉन्टेंट का ऐक्सेस होगा जो आपके <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> पर दिखता है या चलाया जाता है. इसमें ऑडियो, फ़ोटो, पेमेंट संबंधी जानकारी, पासवर्ड, और मैसेज शामिल हैं.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> पर तब ऐप्लिकेशन को स्ट्रीम कर सकेगा, जब तक आप यह अनुमति हटा न दें."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> को <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, आपके <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> में मौजूद ऐप्लिकेशन को स्ट्रीम करने की अनुमति चाहिए"</string> + <!-- no translation found for title_sensor_device_streaming (2395553261097861497) --> + <skip /> + <!-- no translation found for summary_sensor_device_streaming (3413105061195145547) --> + <skip /> + <!-- no translation found for helper_summary_sensor_device_streaming (8860174545653786353) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string> <string name="summary_generic" msgid="1761976003668044801">"यह ऐप्लिकेशन, आपके फ़ोन और चुने हुए डिवाइस के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index 17b45389848c..0b769f036f32 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Želite li dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da streama aplikacije uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na uređaj <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što je vidljivo ili se reproducira na uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, uključujući zvuk, fotografije, podatke o plaćanju, zaporke i poruke.<br/><br/>Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> moći će streamati aplikacije na uređaj <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za streaming aplikacija s vašeg uređaja <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Želite li aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dopustiti streaming zvuka i značajki sustava između uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> i <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> imat će pristup svemu što se reproducira na vašem uređaju <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> moći će streamati zvuk na uređaj <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> dok ne uklonite pristup za to dopuštenje."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime uređaja <xliff:g id="DEVICE_NAME">%2$s</xliff:g> za streaming zvuka i značajki sustava između vaših uređaja."</string> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="1761976003668044801">"Ta će aplikacija moći sinkronizirati podatke između vašeg telefona i odabranog uređaja, primjerice ime pozivatelja"</string> <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index 4b0dd491543d..69bd41b28f63 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> számára a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> alkalmazásainak streamelését a következőre: <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet a(z) <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> minden látható vagy lejátszható tartalmához, így az audiotartalmakhoz, fényképekhez, fizetési adatokhoz, jelszavakhoz és üzenetekhez is.<br/><br/>Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_2">%1$s</xliff:g> képes lesz majd az alkalmazások <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> eszközre való streamelésére."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az alkalmazások következőről való streameléséhez: <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> számára a hang- és rendszerfunkciók streamelését a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> és a(z) <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> között?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> hozzáférhet majd mindenhez, ami a(z) <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> eszközön lejátszásra kerül.<br/><br/>Amíg Ön el nem távolítja az ehhez az engedélyhez való hozzáférést, a(z) <xliff:g id="APP_NAME_2">%1$s</xliff:g> képes lesz majd audiotartalmakat streamelni a(z)<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> eszközre."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nevében az audio- és rendszerfunkcióknak az Ön eszközei közötti streameléséhez."</string> <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string> <string name="summary_generic" msgid="1761976003668044801">"Ez az alkalmazás képes lesz szinkronizálni az olyan információkat a telefon és a kiválasztott eszköz között, mint például a hívó fél neve."</string> <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index 744168b4e7d8..27cd9751d824 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին հեռարձակել ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ի հավելվածները <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> սարքին։"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածին հասանելի կլինի ձեր <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-ում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, վճարային տեղեկությունները, գաղտնաբառերը և հաղորդագրությունները։<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> հավելվածը կկարողանա հավելվածներ հեռարձակել <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> սարքին, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ից հավելվածներ հեռարձակելու համար"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին աուդիո և համակարգի գործառույթներ հեռարձակել ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ի և <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>-ի միջև"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածին հասանելի կլինի ձեր <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-ում նվագարկվող բովանդակությունը։<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> հավելվածը կկարողանա աուդիո հեռարձակել <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-ին, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև աուդիո և համակարգի գործառույթներ հեռարձակելու համար։"</string> <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string> <string name="summary_generic" msgid="1761976003668044801">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և ընտրված սարքի տվյալները, օր․՝ զանգողի անունը"</string> <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index 86e891899268..6ec3392a02ad 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> melakukan streaming aplikasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ke <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang ditampilkan atau diputar di <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, termasuk audio, foto, info pembayaran, sandi, dan pesan.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat melakukan streaming aplikasi ke <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hingga Anda menghapus izin ini."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk melakukan streaming aplikasi dari <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> Anda"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> melakukan streaming audio dan fitur sistem antara <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> dan <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan memiliki akses ke apa pun yang diputar di <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> Anda.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat melakukan streaming audio ke <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hingga Anda menghapus akses ke izin ini."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> meminta izin untuk melakukan streaming audio dan fitur sistem antar-perangkat Anda."</string> <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string> <string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string> <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index 7294e160a6ee..f1b6ced64d69 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að streyma forritum <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> í <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem er sýnilegt eða spilað í <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, þ.m.t. hljóði, myndum, greiðsluupplýsingum, aðgangsorðum og skilaboðum.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> getur streymt forritum í <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> þar til þú fjarlægir þessa heimild."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir hönd <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma forritum úr <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að streyma hljóði og kerfiseiginleikum á milli <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> og <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> fær aðgang að öllu sem þú spilar í <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> mun geta streymt hljóði í <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> þar til þú afturkallar heimildina."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> biður um heimild fyrir hönd <xliff:g id="DEVICE_NAME">%2$s</xliff:g> til að streyma hljóði og kerfiseiginleikum á milli tækjanna þinna."</string> <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string> <string name="summary_generic" msgid="1761976003668044801">"Þetta forrit mun geta samstillt upplýsingar, t.d. nafn þess sem hringir, á milli símans og valins tækis"</string> <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index fe4cc151e2a7..2afdcbaab8bf 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di riprodurre in streaming le app <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> su <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> avrà accesso a tutti i contenuti visibili o riprodotti dal tuo <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inclusi audio, foto, dati di pagamento, password e messaggi.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sarà in grado di riprodurre in streaming le app su <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> finché non rimuoverai l\'accesso a questa autorizzazione."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede l\'autorizzazione per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per riprodurre in streaming le app dal tuo <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di riprodurre in streaming funzionalità di sistema e audio tra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> e <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> avrà accesso a tutto ciò che viene riprodotto sul tuo <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sarà in grado di riprodurre in streaming l\'audio su <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> finché non rimuoverai l\'accesso a questa autorizzazione."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede l\'autorizzazione per conto di <xliff:g id="DEVICE_NAME">%2$s</xliff:g> per riprodurre in streaming funzionalità di sistema e audio tra i tuoi dispositivi."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"Questa app potrà sincronizzare informazioni, ad esempio il nome di un chiamante, tra il telefono e il dispositivo scelto"</string> <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index 16000312e31f..4181e6278d4f 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"לאשר לאפליקציית <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לשדר את האפליקציות של ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ל-<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שרואים או מפעילים ב-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, כולל אודיו, תמונות, פרטי תשלום, סיסמאות והודעות.<br/><br/>לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> תהיה אפשרות לשדר אפליקציות ל-<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> עד שהגישה להרשאה הזו תוסר."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה ל-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> כדי לשדר אפליקציות מה<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"לאשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לשדר תכונות מערכת ואודיו בין ה<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> שלך לבין <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"לאפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> תהיה גישה לכל מה שיופעל במכשיר <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>האפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> תוכל לשדר אודיו אל <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> עד שההרשאה הזו תוסר."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת בשם <xliff:g id="DEVICE_NAME">%2$s</xliff:g> הרשאה כדי לשדר תכונות מערכת ואודיו בין המכשירים שלך."</string> <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string> <string name="summary_generic" msgid="1761976003668044801">"האפליקציה הזו תוכל לסנכרן מידע, כמו השם של מישהו שמתקשר, מהטלפון שלך למכשיר שבחרת"</string> <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index 639e8bca45a5..5974c6b1679c 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> のアプリを <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> にストリーミングすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可しますか?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、音声、写真、お支払い情報、パスワード、メッセージを含め、<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> で表示、再生されるすべてのコンテンツにアクセスできるようになります。<br/><br/>この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_2">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> にアプリをストリーミングできます。"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、アプリを <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> からストリーミングする権限をリクエストしています"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> と <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> との間で音声やシステム機能をストリーミングすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可しますか?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> は、<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> で再生されるすべてのコンテンツにアクセスできるようになります。<br/><br/>この権限へのアクセス権を削除するまで、<xliff:g id="APP_NAME_2">%1$s</xliff:g> は <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> に音声をストリーミングできます。"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_NAME">%2$s</xliff:g> に代わって、デバイス間で音声やシステム機能をストリーミングする権限をリクエストしています。"</string> <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string> <string name="summary_generic" msgid="1761976003668044801">"このアプリは、あなたのスマートフォンと選択したデバイスとの間で、通話相手の名前などの情報を同期できるようになります"</string> <string name="consent_yes" msgid="8344487259618762872">"許可"</string> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index 949d64b821c0..de1c8e1a19b7 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"გსურთ, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს მისცეთ თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის აპების სტრიმინგის საშუალება <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>-ზე?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> მიიღებს წვდომას ყველაფერზე, რაც ჩანს ან უკრავს <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-ზე, მათ შორის, აუდიოზე, ფოტოებზე, პაროლებსა და შეტყობინებებზე.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> შეძლებს აპების სტრიმინგს <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-ზე მანამ, სანამ თქვენ არ გააუქმებთ წვდომას ამ ნებართვაზე."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით აპების სტრიმინგისთვის თქვენი <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-იდან"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"გსურთ, ნება დართოთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს აუდიოს და სისტემის ფუნქციების სტრიმინგზე თქვენს <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-სა და <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>-ს შორის?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> მიიღებს წვდომას ყველაფერზე, რაც უკრავს თქვენს <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>-ზე.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> შეძლებს აუდიოს სტრიმინგს <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-ზე, სანამ თქვენ გააუქმებთ წვდომას ამ ნებართვაზე."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს ნებართვას <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ის სახელით, რათა მოახდინოს აუდიოს და სისტემის სხვა ფუნქციების სტრიმინგი თქვენს მოწყობილობებს შორის."</string> <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string> <string name="summary_generic" msgid="1761976003668044801">"ეს აპი შეძლებს ინფორმაციის სინქრონიზებას თქვენს ტელეფონსა და თქვენ მიერ არჩეულ მოწყობილობას შორის, მაგალითად, იმ ადამიანის სახელის, რომელიც გირეკავთ"</string> <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index 835154263673..27492a035e8a 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына құрылғыңыздағы (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) қолданбаларды <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> құрылғысына трансляциялауға рұқсат берілсін бе?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы құрылғыда (<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>) көрінетін не ойнатылатын барлық контентті, соның ішінде аудиофайлдарды, фотосуреттерді, төлем туралы ақпаратты, құпия сөздер мен хабарларды пайдалана алады.<br/><br/>Осы рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_2">%1$s</xliff:g> қолданбасы құрылғыға (<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>) қолданбаларды трансляциялай алады."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыдағы (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>) қолданбаларды трансляциялауға рұқсат сұрайды."</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> құрылғыңыз бен <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> құрылғысы арасында аудио және жүйе функцияларын трансляциялауға рұқсат берілсін бе?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> құрылғыңызда ойнатылатын барлық контентті пайдалана алады.<br/><br/>Бұл рұқсатты өшірмесеңіз, <xliff:g id="APP_NAME_2">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> құрылғысына аудионы трансляциялай алады."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_NAME">%2$s</xliff:g> атынан құрылғыларыңыз арасында аудио және жүйе функцияларын трансляциялауға рұқсат сұрайды."</string> <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string> <string name="summary_generic" msgid="1761976003668044801">"Бұл қолданба телефон мен таңдалған құрылғы арасында деректі (мысалы, қоңырау шалушының атын) синхрондай алады."</string> <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index 79ec5f18437d..55216e590683 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្សាយកម្មវិធីលើ<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>របស់អ្នកទៅ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ឬ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញ ឬត្រូវបានចាក់នៅលើ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> រួមទាំងសំឡេង រូបថត ព័ត៌មាននៃការទូទាត់ប្រាក់ ពាក្យសម្ងាត់ និងសារ។<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> នឹងអាចផ្សាយកម្មវិធីទៅ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ដើម្បីផ្សាយកម្មវិធីពី<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>របស់អ្នក"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចាក់សំឡេង និងមុខងារប្រព័ន្ធរវាង <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> និង <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> របស់អ្នកឬ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> នឹងមានសិទ្ធិចូលប្រើអ្វីៗដែលត្រូវបានចាក់នៅលើ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> របស់អ្នក។<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> នឹងអាចចាក់សំឡេងទៅ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> រហូតទាល់តែអ្នកដកសិទ្ធិចូលប្រើការអនុញ្ញាតនេះចេញ។"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ដើម្បីចាក់សំឡេង និងមុខងារប្រព័ន្ធរវាងឧបករណ៍របស់អ្នក។"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string> <string name="summary_generic" msgid="1761976003668044801">"កម្មវិធីនេះនឹងអាចធ្វើសមកាលកម្មព័ត៌មាន ដូចជាឈ្មោះមនុស្សដែលហៅទូរសព្ទជាដើម រវាងឧបករណ៍ដែលបានជ្រើសរើស និងទូរសព្ទរបស់អ្នក"</string> <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 7cf406992472..7dcb4e379637 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಆ್ಯಪ್ಗಳನ್ನು <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ಗೆ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲದಕ್ಕೂ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ಗೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME_2">%1$s</xliff:g> ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ನಿಂದ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ಮತ್ತು <xliff:g id="DEVICE_NAME">%3$s</xliff:g> ರ ನಡುವೆ ಆಡಿಯೋ ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸಬೇಕೆ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುವ ಯಾವುದಕ್ಕೂ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ನೀವು ಈ ಅನುಮತಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ <xliff:g id="APP_NAME_2">%1$s</xliff:g> ಗೆ ಆಡಿಯೋಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ಸಾಧನಕ್ಕೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆಡಿಯೋ ಮತ್ತು ಸಿಸ್ಟಮ್ ಫೀಚರ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ."</string> <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string> <string name="summary_generic" msgid="1761976003668044801">"ಮೊಬೈಲ್ ಫೋನ್ ಮತ್ತು ಆಯ್ಕೆಮಾಡಿದ ಸಾಧನದ ನಡುವೆ, ಕರೆ ಮಾಡುವವರ ಹೆಸರಿನಂತಹ ಮಾಹಿತಿಯನ್ನು ಸಿಂಕ್ ಮಾಡಲು ಈ ಆ್ಯಪ್ಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ"</string> <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index c3843633a07b..ff8ed1638062 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>의 앱을 <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> 기기로 스트리밍하도록 허용하시겠습니까?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>에서 오디오, 사진, 결제 정보, 비밀번호, 메시지 등 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>에 표시되거나 해당 기기에서 재생되는 모든 항목에 액세스할 수 있습니다.<br/><br/>이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_2">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> 기기로 앱을 스트리밍할 수 있습니다."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>의 앱을 스트리밍할 권한을 요청하고 있습니다."</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 기기와 <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> 기기 간에 오디오 및 시스템 기능을 스트리밍하도록 허용하시겠습니까?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> 앱이 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>에서 재생되는 모든 항목에 액세스할 수 있습니다.<br/><br/>이 권한에 대한 액세스를 삭제할 때까지 <xliff:g id="APP_NAME_2">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> 기기로 오디오를 스트리밍할 수 있습니다."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 대신 기기 간에 오디오 및 시스템 기능을 스트리밍할 권한을 요청하고 있습니다."</string> <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string> <string name="summary_generic" msgid="1761976003668044801">"이 앱에서 휴대전화와 선택한 기기 간에 정보(예: 발신자 이름)를 동기화할 수 있게 됩니다."</string> <string name="consent_yes" msgid="8344487259618762872">"허용"</string> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 70bdf1f8336a..8c39dd2dea6f 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздөгү колдонмолорду <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> түзмөгүнө алып ойнотууга уруксат бересизби?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> түзмөгүңүздө көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөргө кире алат.<br/><br/>Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> түзмөгүндөгү колдонмолорду алып ойното алат."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> түзмөгүңүздөн колдонмолорду алып ойнотуу үчүн <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүнүн атынан уруксат сурап жатат"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> жана <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> түзмөктөрүнүн ортосунда аудиону жана тутумдун башка функцияларын алып ойнотууга уруксат бересизби?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> түзмөгүндө ойнотулган бардык нерселерге мүмкүнчүлүк ала алат.<br/><br/>Бул уруксатты алып салмайынча, <xliff:g id="APP_NAME_2">%1$s</xliff:g> аудиону <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> түзмөгүнө алып ойното алат."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрдүн ортосунда аудиону жана тутумдун башка функцияларын алып ойнотууга уруксат сурап жатат."</string> <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string> <string name="summary_generic" msgid="1761976003668044801">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана тандалган түзмөк менен шайкештирет"</string> <string name="consent_yes" msgid="8344487259618762872">"Ооба"</string> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index f8da499e63ba..a7cc51e55c2d 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ອະນຸຍາດໃຫ້ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ສະຕຣີມແອັບຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານໄປຫາ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ບໍ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ປາກົດ ຫຼື ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, ເຊິ່ງຮວມທັງສຽງ, ຮູບພາບ, ຂໍ້ມູນການຈ່າຍເງິນ, ລະຫັດຜ່ານ ແລະ ຂໍ້ຄວາມ.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ຈະສາມາດສະຕຣີມແອັບໄປຫາ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບຈາກ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ຂອງທ່ານ"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"ອະນຸຍາດໃຫ້ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ສະຕຣີມສຽງ ແລະ ຄຸນສົມບັດຂອງລະບົບລະຫວ່າງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ຂອງທ່ານກັບ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ບໍ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກຢ່າງທີ່ຫຼິ້ນຢູ່ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ຂອງທ່ານ.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ຈະສາມາດສະຕຣີມສຽງໄປຫາ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ໄດ້ຈົນກວ່າທ່ານຈະລຶບສິດເຂົ້າເຖິງການອະນຸຍາດນີ້ອອກ."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ເພື່ອສະຕຣີມສຽງ ແລະ ຄຸນສົມບັດຂອງລະບົບລະຫວ່າງອຸປະກອນຕ່າງໆຂອງທ່ານ."</string> <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string> <string name="summary_generic" msgid="1761976003668044801">"ແອັບນີ້ຈະສາມາດຊິ້ງຂໍ້ມູນ ເຊັ່ນ: ຊື່ຂອງຄົນທີ່ໂທເຂົ້າ, ລະຫວ່າງໂທລະສັບຂອງທ່ານ ແລະ ອຸປະກອນທີ່ເລືອກໄວ້ໄດ້"</string> <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 7a5f347073a4..b537508b8f7b 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Leisti programai <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> srautu perduoti <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> programas į <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą „<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>“ matomą ar leidžiamą turinį, įskaitant garso įrašus, nuotraukas, mokėjimo informaciją, slaptažodžius ir pranešimus.<br/><br/>Programa „<xliff:g id="APP_NAME_2">%1$s</xliff:g>“ galės perduoti srautu programas į „<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš jūsų <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Leisti programai <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> srautu perduoti garsą ir sistemos funkcijas iš <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> į <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ galės pasiekti visą jūsų „<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>“ leidžiamą turinį.<br/><br/&gtPrograma „<xliff:g id="APP_NAME_2">%1$s</xliff:g>“ galės srautu perduoti garsą į „<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>“, kol pašalinsite prieigą prie šio leidimo."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo „<xliff:g id="DEVICE_NAME">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti garsą ir sistemos funkcijas iš vieno įrenginio į kitą."</string> <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string> <string name="summary_generic" msgid="1761976003668044801">"Ši programa galės sinchronizuoti tam tikrą informaciją, pvz., skambinančio asmens vardą, su jūsų telefonu ir pasirinktu įrenginiu"</string> <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index 2d79d530ded9..e310fe2ca887 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> straumēt <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> lietotnes ierīcē <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ekrānā parādītajam vai atskaņotajam saturam, tostarp audio, fotoattēliem, maksājumu informācijai, parolēm un ziņojumiem.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> varēs straumēt lietotnes ierīcē <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju <xliff:g id="DEVICE_NAME">%2$s</xliff:g> vārdā straumēt lietotnes no jūsu ierīces <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>."</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Vai atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> straumēt audio un sistēmas funkcijas starp jūsu ierīci <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> un ierīci <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Lietotne <xliff:g id="APP_NAME_0">%1$s</xliff:g> varēs piekļūt visam jūsu ierīces <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> atskaņotajam saturam.<br/><br/>Lietotne <xliff:g id="APP_NAME_2">%1$s</xliff:g> varēs straumēt audio ierīcē <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, līdz noņemsiet piekļuvi šai atļaujai."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt audio un sistēmas funkcijas starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_NAME">%2$s</xliff:g>."</string> <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string> <string name="summary_generic" msgid="1761976003668044801">"Šī lietotne varēs sinhronizēt informāciju (piemēram, zvanītāja vārdu) starp jūsu tālruni un izvēlēto ierīci"</string> <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index a69a12e49b34..08b422bc12cf 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Да се дозволи <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да ги стримува апликациите од <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ќе има пристап до сè што е видливо или репродуцирано на <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, вклучувајќи ги и аудиото, фотографиите, податоците за плаќање, лозинките и пораките.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ќе може да стримува апликации на <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> сѐ додека не ја отстраните дозволава."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да стримува апликации од вашиот <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Да се дозволи <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да стримува аудио и системски функции меѓу вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> и <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ќе има пристап до сè што е пуштено на вашиот <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ќе може да стримува аудио на <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> сѐ додека не ја отстраните дозволава."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на <xliff:g id="DEVICE_NAME">%2$s</xliff:g> за да стримува аудио и системски функции меѓу вашите уреди."</string> <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string> <string name="summary_generic" msgid="1761976003668044801">"Оваа апликација ќе може да ги синхронизира податоците како што се имињата на јавувачите помеѓу вашиот телефон и избраниот уред"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index 1a19f224c998..ab9671ed540f 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> എന്നതിന്റെ ആപ്പുകൾ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> എന്നതിലേക്ക് സ്ട്രീം ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ഓഡിയോ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിവരങ്ങൾ, പാസ്വേഡുകൾ, സന്ദേശങ്ങൾ എന്നിവ ഉൾപ്പെടെ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> എന്നതിൽ ദൃശ്യമാകുന്നതോ പ്ലേ ചെയ്യുന്നതോ എല്ലാ എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.<br/><br/>നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_2">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> എന്നതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാനാകും."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> എന്നതിൽ നിന്ന് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്നതിന്റെ പേരിൽ <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ നിങ്ങളുടെ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> എന്നിവ തമ്മിൽ ഓഡിയോയും സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ അനുവദിക്കണോ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്ന എല്ലാത്തിലേക്കും <xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും.<br/><br/>നിങ്ങൾ ഈ അനുമതിയിലേക്കുള്ള ആക്സസ് നീക്കം ചെയ്യുന്നത് വരെ <xliff:g id="APP_NAME_2">%1$s</xliff:g> എന്നതിന് <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> എന്നതിലേക്ക് ഓഡിയോ സ്ട്രീം ചെയ്യാനാകും."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ഓഡിയോയും സിസ്റ്റം ഫീച്ചറുകളും സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> എന്ന ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നത് അനുമതി അഭ്യർത്ഥിക്കുന്നു."</string> <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string> <string name="summary_generic" msgid="1761976003668044801">"വിളിക്കുന്നയാളുടെ പേര് പോലുള്ള വിവരങ്ങൾ നിങ്ങളുടെ ഫോണിനും തിരഞ്ഞെടുത്ത ഉപകരണത്തിനും ഇടയിൽ സമന്വയിപ്പിക്കുന്നതിന് ഈ ആപ്പിന് കഴിയും"</string> <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 96951ad9c2d7..7b0a08ae1aca 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н аппыг <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>-д дамжуулахыг зөвшөөрөх үү?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> аудио, зураг, төлбөрийн мэдээлэл, нууц үг, мессеж зэрэг <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> дээр харагдаж, тоглуулж буй аливаа зүйлд хандах эрхтэй болно.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> таныг энэ зөвшөөрөлд хандах эрхийг нь хасах хүртэл <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-д апп дамжуулах боломжтой байх болно."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс таны <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>-с апп дамжуулах зөвшөөрлийг хүсэж байна"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>-н хооронд аудио, системийн онцлогуудыг дамжуулахыг зөвшөөрөх үү?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> дээр тоглуулж буй аливаа зүйлд хандах эрхтэй болно.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> таныг энэ зөвшөөрлийг хасах хүртэл <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>-д аудио дамжуулах боломжтой байх болно."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс таны төхөөрөмжүүдийн хооронд аудио, системийн онцлогуудыг дамжуулах зөвшөөрлийг хүсэж байна."</string> <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string> <string name="summary_generic" msgid="1761976003668044801">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон сонгосон төхөөрөмжийн хооронд синк хийх боломжтой болно"</string> <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index 9520a328d9a2..e18f86e5cdfb 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ला अॅप्स <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>वर स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला ऑडिओ, फोटो, पेमेंट माहिती, पासवर्ड आणि मेसेज यांसह तुमच्या <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> वर दिसणाऱ्या किंवा प्ले होणाऱ्या सर्व गोष्टींचा अॅक्सेस असेल.<br/><br/>तुम्ही या परवानगीचा अॅक्सेस काढून टाकेपर्यंत <xliff:g id="APP_NAME_2">%1$s</xliff:g> हे <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> वर ॲप्स स्ट्रीम करू शकेल."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> वरून अॅप्स आणि सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> आणि <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> दरम्यान ऑडिओ आणि सिस्टीम वैशिष्ट्ये स्ट्रीम करू द्यायची आहेत का?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ला तुमच्या <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> वर प्ले केलेल्या कोणत्याही गोष्टीचा अॅक्सेस असेल.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> हे तुम्ही या परवानगीचा अॅक्सेस काढून टाकेपर्यंत <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> वर ऑडिओ स्ट्रीम करू शकेल."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या डिव्हाइसदरम्यान ऑडिओ आणि सिस्टीम वैशिष्ट्ये स्ट्रीम करण्यासाठी <xliff:g id="DEVICE_NAME">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे."</string> <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string> <string name="summary_generic" msgid="1761976003668044801">"हे ॲप तुमचा फोन आणि निवडलेल्या डिव्हाइसदरम्यान कॉल करत असलेल्या एखाद्या व्यक्तीचे नाव यासारखी माहिती सिंक करू शकेल"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index b3c8bd0a4462..31cb3b756c6f 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk menstrim apl <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda kepada <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua kandungan yang dipaparkan atau dimainkan pada <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, termasuk audio, foto, maklumat pembayaran, kata laluan dan mesej.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat menstrim apl kepada <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstrim apl daripada <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> anda"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> menstrim audio dan ciri sistem antara <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda dengan <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> akan mendapat akses kepada semua kandungan yang dimainkan pada <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> anda.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> akan dapat menstrim audio kepada <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> sehingga anda mengalih keluar akses kepada kebenaran ini."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta kebenaran bagi pihak <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstrim audio dan ciri sistem antara peranti anda."</string> <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string> <string name="summary_generic" msgid="1761976003668044801">"Apl ini akan dapat menyegerakkan maklumat seperti nama individu yang memanggil, antara telefon anda dengan peranti yang dipilih"</string> <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index bb4e7c55716e..0b0273f67aae 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အား သင့် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ၏ အက်ပ်များကို <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> တွင် တိုက်ရိုက်ဖွင့်ခွင့်ပြုမလား။"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် အသံ၊ ဓာတ်ပုံ၊ စကားဝှက်နှင့် မက်ဆေ့ဂျ်များအပါအဝင် <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> တွင် မြင်နိုင်သော (သို့) ဖွင့်ထားသော အရာအားလုံးကို သုံးခွင့်ရှိပါမည်။<br/><br/>ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_2">%1$s</xliff:g> သည် <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> တွင် အက်ပ်များကို တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့် <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> မှ အက်ပ်များကို တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"သင်၏ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> နှင့် <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> အကြား အသံနှင့် စနစ်အင်္ဂါရပ်များ တိုက်ရိုက်ဖွင့်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို ခွင့်ပြုမလား။"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> သည် သင်၏ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> တွင် ဖွင့်ထားသော မည်သည့်အရာကိုမဆို သုံးခွင့်ရှိပါမည်။<br/><br/>ဤခွင့်ပြုချက်သုံးခွင့်ကို သင်မဖယ်ရှားမချင်း <xliff:g id="APP_NAME_2">%1$s</xliff:g> သည် <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> တွင် အသံ တိုက်ရိုက်ဖွင့်နိုင်ပါမည်။"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်စက်များအကြား အသံနှင့် စနစ်အင်္ဂါရပ်များ တိုက်ရိုက်ဖွင့်ရန် <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်။"</string> <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string> <string name="summary_generic" msgid="1761976003668044801">"ဤအက်ပ်သည် သင့်ဖုန်းနှင့် ရွေးထားသောစက်အကြား ခေါ်ဆိုသူ၏အမည်ကဲ့သို့ အချက်အလက်ကို စင့်ခ်လုပ်နိုင်ပါမည်"</string> <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index e8adbcd61910..ccb2c572f6f7 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vil du la <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strømme apper fra <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> kan se som vises eller spilles av på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inkludert lyd, bilder, passord og meldinger.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan strømme apper til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> frem til du fjerner tilgangen til denne tillatelsen."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper fra <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Vil du la <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strømme lyd og systemfunksjoner mellom <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> og <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får tilgang til alt som spilles av på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan strømme lyd til <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> frem til du fjerner denne tillatelsen."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme lyd og systemfunksjoner mellom enhetene dine på vegne av <xliff:g id="DEVICE_NAME">%2$s</xliff:g>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="summary_generic" msgid="1761976003668044801">"Denne appen kan synkronisere informasjon som navnet til noen som ringer, mellom telefonen og den valgte enheten"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index 6386057f41b4..203eaeedbd4c 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> मा भएका एपहरू <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> मा स्ट्रिम गर्न दिने हो?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> मा देखिने वा प्ले गरिने अडियो, फोटो, भुक्तानीसम्बन्धी जानकारी, पासवर्ड र म्यासेजलगायतका सबै कुरा एक्सेस गर्न सक्ने छ।<br/><br/>तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_2">%1$s</xliff:g> ले एपहरू <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> मा स्ट्रिम गर्न पाइराख्ने छ।"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंको <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> बाट एपहरू स्ट्रिम गर्ने अनुमति माग्दै छ"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> र <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> का बिचमा अडियो र सिस्टमका सुविधाहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ले तपाईंको <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> मा प्ले गरिने सबै कुरा एक्सेस गर्न सक्ने छ।<br/><br/>तपाईंले यो अनुमति रद्द नगरेसम्म <xliff:g id="APP_NAME_2">%1$s</xliff:g> ले <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> मा अडियो स्ट्रिम गर्न पाइराख्ने छ।"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले डिभाइस <xliff:g id="DEVICE_NAME">%2$s</xliff:g> को तर्फबाट तपाईंका डिभाइसहरूका बिचमा अडियो र सिस्टमका सुविधाहरू स्ट्रिम गर्ने अनुमति माग्दै छ।"</string> <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string> <string name="summary_generic" msgid="1761976003668044801">"यो एपले तपाईंको फोन र तपाईंले छनौट गर्ने डिभाइसका बिचमा कल गर्ने व्यक्तिको नाम जस्ता जानकारी सिंक गर्न सक्ने छ।"</string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index 58c7d4f7c31c..069c00c85cfc 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan om apps van je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> naar <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> te streamen?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat zichtbaar is of wordt afgespeeld op <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, waaronder audio, foto\'s, wachtwoorden en berichten.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan apps naar <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> streamen totdat je dit recht verwijdert."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om apps te streamen vanaf je <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan om audio en systeemfuncties te streamen tussen je <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> en <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> krijgt toegang tot alles wat wordt afgespeeld op je <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan audio naar <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> streamen totdat je de toegang tot dit recht intrekt."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens <xliff:g id="DEVICE_NAME">%2$s</xliff:g> toestemming om audio en systeemfuncties te streamen tussen je apparaten."</string> <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string> <string name="summary_generic" msgid="1761976003668044801">"Deze app kan informatie, zoals de naam van iemand die belt, synchroniseren tussen je telefoon en het gekozen apparaat"</string> <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index d431fb9f43cc..a1a6c9023503 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ର ଆପ୍ସକୁ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ରେ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ଅଡିଓ, ଫଟୋ, ପାସୱାର୍ଡ ଏବଂ ମେସେଜ ସମେତ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।<br/><br/>ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ସକ୍ଷମ ହେବ।"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ରୁ ଆପ୍ସ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ଅନୁରୋଧ କରୁଛି"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"ଆପଣଙ୍କ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ଏବଂ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ମଧ୍ୟରେ ଅଡିଓ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦେବେ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>ରେ ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_NAME_0">%1$s</xliff:g>ର ଆକ୍ସେସ ରହିବ।<br/><br/>ଆପଣ ଏହି ଅନୁମତିକୁ ଆକ୍ସେସ କାଢ଼ି ନଦେବା ପର୍ଯ୍ୟନ୍ତ <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>ରେ ଅଡିଓ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME_2">%1$s</xliff:g> ସକ୍ଷମ ହେବ।"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଅଡିଓ ଏବଂ ସିଷ୍ଟମ ଫିଚରଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ତରଫରୁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି।"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string> <string name="summary_generic" msgid="1761976003668044801">"ଆପଣଙ୍କ ଫୋନ ଏବଂ ବଛାଯାଇଥିବା ଡିଭାଇସ ମଧ୍ୟରେ, କଲ କରୁଥିବା ଯେ କୌଣସି ବ୍ୟକ୍ତିଙ୍କ ନାମ ପରି ସୂଚନା ସିଙ୍କ କରିବାକୁ ଏହି ଆପ ସକ୍ଷମ ହେବ"</string> <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 463a02bab3b0..cd40ec7a5579 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ਦੀਆਂ ਐਪਾਂ ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> \'ਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> \'ਤੇ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> ਤੋਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਆਪਣੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਅਤੇ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> \'ਤੇ ਆਡੀਓ ਅਤੇ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਕੋਲ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> \'ਤੇ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਹਟਾ ਨਹੀਂ ਦਿੰਦੇ, ਉਦੋਂ ਤੱਕ <xliff:g id="APP_NAME_2">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> \'ਤੇ ਆਡੀਓ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ।"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਆਡੀਓ ਅਤੇ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ।"</string> <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string> <string name="summary_generic" msgid="1761976003668044801">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਚੁਣੇ ਗਏ ਡੀਵਾਈਸ ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string> <string name="consent_yes" msgid="8344487259618762872">"ਆਗਿਆ ਦਿਓ"</string> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index dc7977d4e429..b16776631dfc 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Zezwolić aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na strumieniowanie aplikacji na <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na urządzenie <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest widoczne i odtwarzane na <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, w tym do dźwięku, zdjęć, haseł i wiadomości.<br/><br/>Aplikacja <xliff:g id="APP_NAME_2">%1$s</xliff:g> będzie mogła strumieniować aplikacje na urządzenie <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o pozwolenie na strumieniowanie aplikacji z urządzenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Zezwolić aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na strumieniowanie dźwięku i funkcji systemowych między urządzeniami <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> i <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> będzie miała dostęp do wszystkiego, co jest odtwarzane na urządzeniu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>Aplikacja <xliff:g id="APP_NAME_2">%1$s</xliff:g> będzie mogła strumieniować dźwięk na urządzenie <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dopóki nie usuniesz dostępu do tego uprawnienia."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o pozwolenie na strumieniowanie dźwięku i funkcji systemowych między Twoimi urządzeniami."</string> <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string> <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacja może synchronizować informacje takie jak imię i nazwisko osoby dzwoniącej między Twoim telefonem i wybranym urządzeniem"</string> <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index 88cf563c056f..a6c09d06f143 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.<br/><br/>O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming de áudio e recursos do sistema entre o <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> e o <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que for aberto no seu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de áudio para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de áudio e recursos do sistema entre seus dispositivos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index 34034f003eb6..01af6df4f89d 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream das apps do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o dispositivo <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que seja visível ou reproduzido no dispositivo <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.<br/><br/>A app <xliff:g id="APP_NAME_2">%1$s</xliff:g> vai poder fazer stream de apps para o dispositivo <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até remover o acesso a esta autorização."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream de áudio e funcionalidades do sistema entre o seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> e o <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> vai ter acesso a tudo o que for reproduzido no seu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>A app <xliff:g id="APP_NAME_2">%1$s</xliff:g> vai poder fazer stream de áudio para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até remover o acesso a esta autorização."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de áudio e funcionalidades do sistema entre os seus dispositivos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index 88cf563c056f..a6c09d06f143 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming dos aplicativos do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para o <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que estiver visível ou for aberto no <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, incluindo áudios, fotos, informações de pagamento, senhas e mensagens.<br/><br/>O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de aplicativos para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps do seu <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming de áudio e recursos do sistema entre o <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> e o <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> terá acesso a tudo que for aberto no seu <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> poderá fazer streaming de áudio para o <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> até que você remova o acesso a essa permissão."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de áudio e recursos do sistema entre seus dispositivos."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index 002c55211819..2b8b5e10b792 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să redea în stream aplicații de pe <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pe <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul vizibil sau redat pe <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inclusiv conținut audio, fotografii, informații de plată, parole și mesaje.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> va putea să redea în stream aplicații pe <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> până când elimini accesul la această permisiune."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream aplicații de pe <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Permiți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să redea în stream conținut audio și funcții de sistem între <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> și <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> va avea acces la tot conținutul redat pe <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> va putea să redea în stream conținut audio pe <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> până când elimini accesul la această permisiune."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de a reda în stream conținut audio și funcții de sistem între dispozitive."</string> <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string> <string name="summary_generic" msgid="1761976003668044801">"Aplicația va putea să sincronizeze informații, cum ar fi numele unui apelant, între telefonul tău și dispozitivul ales"</string> <string name="consent_yes" msgid="8344487259618762872">"Permite"</string> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index 6f06a2a15820..605fbd9bbc60 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслировать приложения с вашего устройства (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) на устройство <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"У приложения \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" будет доступ ко всему, что показывается или воспроизводится на устройстве \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\", включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.<br/><br/>Приложение \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" сможет транслировать приложения на устройство \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пока вы не отзовете разрешение."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения с устройства (<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>)."</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслировать аудио и системные функции между вашим устройством (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) и устройством <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Приложение \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" получит доступ ко всему, что воспроизводится на устройстве \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\".<br/><br/>Приложение \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" сможет транслировать аудио на устройство \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", пока вы не отзовете это разрешение."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать аудио и системные функции между устройствами."</string> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string> <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index c4b29661e170..63024cac9c25 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> හි යෙදුම් <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> වෙත ප්රවාහ කිරීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඉඩ දෙන්න ද?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ශ්රව්ය, ඡායාරූප, ගෙවීම් තොරතුරු, මුරපද සහ පණිවිඩ ඇතුළුව <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> හි දෘශ්යමාන හෝ වාදනය වන ඕනෑම දෙයකට ප්රවේශය ඇත.<br/><br/>ඔබ මෙම අවසරයට ප්රවේශය ඉවත් කරන තෙක් <xliff:g id="APP_NAME_2">%1$s</xliff:g> හට <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> වෙත යෙදුම් ප්රවාහ කිරීමට හැකි වනු ඇත."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් ඔබේ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> වෙතින් යෙදුම් ප්රවාහ කිරීමට අවසර ඉල්ලා සිටියි"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> සහ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> අතර ශ්රව්ය සහ පද්ධති විශේෂාංග ප්රවාහ කිරීමට ඉඩ දෙන්න ද?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> හට ඔබේ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> හි වාදනය වන ඕනෑම දෙයකට ප්රවේශය ලැබෙනු ඇත.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> හට මෙම අවසරයට ප්රවේශය ඉවත් කරන තුරු <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> වෙත ශ්රව්ය ප්රවාහ කිරීමට හැකි වනු ඇත."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබේ උපාංග අතර ශ්රව්ය සහ පද්ධති විශේෂාංග ප්රවාහ කිරීමට <xliff:g id="DEVICE_NAME">%2$s</xliff:g> වෙනුවෙන් අවසර ඉල්ලා සිටී."</string> <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string> <string name="summary_generic" msgid="1761976003668044801">"මෙම යෙදුමට ඔබේ දුරකථනය සහ තෝරා ගත් උපාංගය අතර, අමතන කෙනෙකුගේ නම වැනි, තතු සමමුහුර්ත කිරීමට හැකි වනු ඇත"</string> <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index bf96c5c26bae..f80ceca5ead9 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovať aplikácie zo zariadenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> do zariadenia <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa zobrazuje alebo prehráva v zariadení <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> vrátane zvuku, fotiek, platobných údajov, hesiel a správ.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> bude môcť streamovať aplikácie do zariadenia <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje v mene zariadenia <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie z vášho zariadenia <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovať zvuk a systémové funkcie medzi zariadením <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> a zariadením <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> bude mať prístup k všetkému, čo sa prehráva v zariadení <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>Aplikácia <xliff:g id="APP_NAME_2">%1$s</xliff:g> bude môcť streamovať zvuk do zariadenia <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, kým prístup k tomuto povoleniu neodstránite."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať zvuk a systémové funkcie medzi vašimi zariadeniami."</string> <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string> <string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string> <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 2c1edcd01899..2db2b7861003 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Ali aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite, da pretočno predvaja aplikacije naprave <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> v napravi <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar je prikazano ali se predvaja v napravi <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, vključno z zvokom, fotografijami, podatki za plačilo, gesli in sporočili.<br/><br/>Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> bo lahko pretočno predvajala aplikacije v napravo <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>, dokler ne odstranite dostopa do tega dovoljenja."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave <xliff:g id="DEVICE_NAME">%2$s</xliff:g> zahteva dovoljenje za pretočno predvajanje aplikacij iz naprave <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Ali aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite pretočno predvajanje zvoka in sistemskih funkcij med napravo »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« in napravo <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> bo imela dostop do vsega, kar se predvaja v napravi »<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>«.<br/><br/>Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> bo lahko pretočno predvajala zvok v napravo »<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>«, dokler ne odstranite dostopa do tega dovoljenja."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje zvoka in sistemskih funkcij v vaših napravah."</string> <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string> <string name="summary_generic" msgid="1761976003668044801">"Ta aplikacija bo lahko sinhronizirala podatke, na primer ime klicatelja, v telefonu in izbrani napravi."</string> <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 33d243017248..45f008db9594 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet nga <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> te <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> do të ketë qasje te çdo gjë që është e dukshme ose që luhet te <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, duke përfshirë audion, fotografitë, informacionet për pagesën, fjalëkalimet dhe mesazhet.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> do të mund t\'i transmetojë aplikacionet në <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> derisa ta heqësh qasjen për këtë leje."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të transmetuar aplikacione nga <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të transmetojë audion dhe veçoritë e sistemit mes <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> dhe <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> do të ketë qasje në çdo gjë që luhet në pajisjen tënde <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> do të mund të transmetojë audion te <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> derisa të heqësh qasjen për këtë leje."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_NAME">%2$s</xliff:g> për të transmetuar audion dhe veçoritë e sistemit mes pajisjeve të tua"</string> <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string> <string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string> <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string> diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml index 582e832aeff2..650d2d892e90 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Желите да дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> стримује апликације уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се види или пушта на уређају <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, укључујући звук, слике, информације о плаћању, лозинке и поруке.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ће моћи да стримује апликације на <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује апликације са уређаја <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Желите да дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> стримује звук и системске функције између уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> и <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ће имати приступ свему што се пушта на уређају <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> ће моћи да стримује звук на <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> док не уклоните приступ овој дозволи."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> тражи дозволу у име уређаја <xliff:g id="DEVICE_NAME">%2$s</xliff:g> да стримује звук и системске функције између уређаја."</string> <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string> <string name="summary_generic" msgid="1761976003668044801">"Ова апликација ће моћи да синхронизује податке, попут имена особе која упућује позив, између телефона и одабраног уређаја"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index cb7b7094fa1d..d28bff87b674 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vill du tillåta <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> att streama appar på din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> till <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som visas eller spelas upp på <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, inklusive ljud, foton, betalningsuppgifter, lösenord och meddelanden.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streama appar till <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att streama appar från din <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Vill du tillåta att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamar ljud och systemfunktioner mellan <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> och <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> får åtkomst till allt som spelas upp på din <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> kan streama ljud till <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> tills du tar bort åtkomsten till den här behörigheten."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet för <xliff:g id="DEVICE_NAME">%2$s</xliff:g> att streama ljud och systemfunktioner mellan dina enheter."</string> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="summary_generic" msgid="1761976003668044801">"Den här appen kommer att kunna synkronisera information mellan telefonen och den valda enheten, till exempel namnet på någon som ringer"</string> <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index 6d623e50fcc5..afa3ea63b5bf 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> itiririshe programu za <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako kwenye <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Programu ya <xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachoonekana au kuchezwa kwenye <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, ikiwa ni pamoja na sauti, picha, maelezo ya malipo, manenosiri na ujumbe.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> itaweza kutiririsha programu kwenye <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ili itiririshe programu kwenye <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yako"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> itiririshe sauti na vipengele vya mfumo kati ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> na <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> yako?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> itafikia chochote kinachochezwa kwenye <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> yako.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> itaweza kutiririsha sauti kwenye <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hadi utakapoondoa ruhusa hii."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ili itiririshe sauti na vipengele vya mfumo kati ya vifaa vyako."</string> <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string> <string name="summary_generic" msgid="1761976003668044801">"Programu hii itaweza kusawazisha maelezo, kama vile jina la mtu anayepiga simu, kati ya simu yako na kifaa ulichochagua"</string> <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string> diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml index 202ec79c64e1..fd2038a07dd6 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சாதனத்தின் ஆப்ஸை <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> சாதனத்தில் ஸ்ட்ரீம் செய்ய <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ஆடியோ, படங்கள், பேமெண்ட் தகவல்கள், கடவுச்சொற்கள், மெசேஜ்கள் உட்பட <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> சாதனத்தில் காட்டப்படுகின்ற/பிளே செய்யப்படுகின்ற அனைத்தையும் <xliff:g id="APP_NAME_0">%1$s</xliff:g> அணுகும்.<br/><br/>இந்த அனுமதிக்கான அணுகலை நீங்கள் அகற்றும் வரை <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> சாதனத்தில் ஆப்ஸை <xliff:g id="APP_NAME_2">%1$s</xliff:g> ஸ்ட்ரீம் செய்ய முடியும்."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"உங்கள் <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> சாதனத்தில் இருந்து ஆப்ஸை ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கேட்கிறது"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> மற்றும் <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> சாதனங்களுக்கு இடையே ஆடியோவையும் சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்ய <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"உங்கள் <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> சாதனத்தில் பிளே ஆகும் அனைத்திற்குமான அணுகலை <xliff:g id="APP_NAME_0">%1$s</xliff:g> கொண்டிருக்கும்.<br/><br/>இந்த அனுமதிக்கான அணுகலை நீங்கள் அகற்றும் வரை <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> சாதனத்தில் ஆடியோவை <xliff:g id="APP_NAME_2">%1$s</xliff:g> ஸ்ட்ரீம் செய்ய முடியும்."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"உங்கள் சாதனங்களுக்கு இடையே ஆடியோவையும் சிஸ்டம் அம்சங்களையும் ஸ்ட்ரீம் செய்ய <xliff:g id="DEVICE_NAME">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> அனுமதி கேட்கிறது."</string> <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string> <string name="summary_generic" msgid="1761976003668044801">"அழைப்பவரின் பெயர் போன்ற தகவலை உங்கள் மொபைல் மற்றும் தேர்வுசெய்த சாதனத்திற்கு இடையில் இந்த ஆப்ஸால் ஒத்திசைக்க முடியும்"</string> <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index 34671f9a0433..8466921f3634 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> యాప్లను <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>కు స్ట్రీమ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"ఆడియో, ఫోటోలు, పేమెంట్ సమాచారం, పాస్వర్డ్లతో సహా <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా <xliff:g id="APP_NAME_0">%1$s</xliff:g>కు యాక్సెస్ ఉంటుంది.<br/><br/>మీరు ఈ అనుమతికి యాక్సెస్ను తీసివేసే వరకు <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>కు యాప్లను స్ట్రీమ్ చేయగలదు."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"మీ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> నుండి యాప్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> మధ్య ఆడియో, సిస్టమ్ ఫీచర్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g>ను అనుమతించాలా?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> మీ <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>లో ప్లే చేయబడిన దేనికైనా యాక్సెస్ కలిగి ఉంటుంది.<br/><br/>మీరు ఈ అనుమతికి యాక్సెస్ను తీసివేసే వరకు <xliff:g id="APP_NAME_2">%1$s</xliff:g> ఆడియోను <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>కు స్ట్రీమ్ చేయగలదు."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"మీ పరికరాల మధ్య ఆడియో, సిస్టమ్ ఫీచర్లను స్ట్రీమ్ చేయడానికి <xliff:g id="DEVICE_NAME">%2$s</xliff:g> తరపున <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్ అనుమతిని రిక్వెస్ట్ చేస్తోంది."</string> <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string> <string name="summary_generic" msgid="1761976003668044801">"కాల్ చేస్తున్న వారి పేరు వంటి సమాచారాన్ని ఈ యాప్ మీ ఫోన్ కు, ఎంచుకున్న పరికరానికీ మధ్య సింక్ చేయగలుగుతుంది"</string> <string name="consent_yes" msgid="8344487259618762872">"అనుమతించండి"</string> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index e74f96c7260f..2e7ba3c6a37a 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> สตรีมแอปใน<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ของคุณไปยัง <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ไหม"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่ปรากฏหรือเล่นบน <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ซึ่งรวมถึงเสียง รูปภาพ ข้อมูลการชำระเงิน รหัสผ่าน และข้อความ<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> จะสามารถสตรีมแอปไปยัง <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ได้จนกว่าคุณจะนำการให้สิทธิ์นี้ออก"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมแอปจาก<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>ของคุณ"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> สตรีมเสียงและฟีเจอร์ของระบบระหว่าง<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>กับ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ไหม"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> จะมีสิทธิ์เข้าถึงทุกอย่างที่เล่นบน <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g><br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> จะสามารถสตรีมเสียงไปยัง <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> ได้จนกว่าคุณจะนำการให้สิทธิ์นี้ออก"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> เพื่อสตรีมเสียงและฟีเจอร์ของระบบระหว่างอุปกรณ์ต่างๆ ของคุณ"</string> <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string> <string name="summary_generic" msgid="1761976003668044801">"แอปนี้จะสามารถซิงค์ข้อมูล เช่น ชื่อของบุคคลที่โทรเข้ามา ระหว่างโทรศัพท์ของคุณและอุปกรณ์ที่เลือกไว้ได้"</string> <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index ce907f731bf2..3f4e2af77df9 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-stream ang mga app ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> sa <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa kahit anong nakikita o pine-play sa <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, kasama ang audio, mga larawan, impormasyon sa pagbabayad, mga password, at mga mensahe.<br/><br/>Magagawa ng <xliff:g id="APP_NAME_2">%1$s</xliff:g> na mag-stream ng mga app sa <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Humihingi ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot para sa <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng mga app mula sa iyong <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na mag-stream ng audio at mga feature ng system sa pagitan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> at <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Magkakaroon ng access ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa anumang pine-play sa iyong <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>.<br/><br/>Makakapag-stream ang <xliff:g id="APP_NAME_2">%1$s</xliff:g> ng audio sa <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> hanggang sa alisin mo ang access sa pahintulot na ito."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Humihingi ang <xliff:g id="APP_NAME">%1$s</xliff:g> ng pahintulot para sa <xliff:g id="DEVICE_NAME">%2$s</xliff:g> na mag-stream ng audio at mga feature ng system sa pagitan ng iyong mga device."</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="1761976003668044801">"Magagawa ng app na ito na mag-sync ng impormasyon, tulad ng pangalan ng isang taong tumatawag, sa pagitan ng iyong telepono at ng napiling device"</string> <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 7acad6475875..3e4603bea751 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adlı uygulamanın <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınızdaki uygulamaları <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> cihazına aktarmasına izin verilsin mi?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>; ses, fotoğraflar, ödeme bilgileri, şifreler ve mesajlar da dahil olmak üzere <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> cihazında görünen veya oynatılan her şeye erişebilecek.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> siz bu iznin erişimini kaldırana kadar uygulamaları <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cihazına aktarabilecek."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> adına uygulamaları <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> cihazınızdan aktarmak için izin istiyor"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ve <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> cihazları arasında ses ve sistem özelliklerini aktarmasına izin verilsin mi?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulaması; <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> cihazınızda oynatılan her şeye erişebilecek.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> uygulaması bu iznin erişimini kaldırana kadar sesleri <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cihazına aktarabilecek."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> için cihazlarınız arasında ses ve sistem özelliklerini aktarma izni istiyor."</string> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="summary_generic" msgid="1761976003668044801">"Bu uygulama, arayan kişinin adı gibi bilgileri telefonunuz ve seçili cihaz arasında senkronize edebilir"</string> <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index 50f93d53a660..18adf00c8c5b 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслювати додатки на вашому <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> на пристрій <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> матиме доступ до контенту, що відображається чи відтворюється на пристрої \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\", зокрема до аудіо, фото, платіжної інформації, паролів і повідомлень.<br/><br/>Додаток <xliff:g id="APP_NAME_2">%1$s</xliff:g> зможе транслювати додатки на пристрій \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", поки ви не скасуєте цей дозвіл."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені пристрою \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запитує дозвіл на трансляцію додатків на вашому <xliff:g id="DEVICE_TYPE">%3$s</xliff:g>"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслювати аудіо й системні функції між пристроями (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> і <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> матиме доступ до контенту, що відтворюється на пристрої \"<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>\".<br/><br/>Додаток <xliff:g id="APP_NAME_2">%1$s</xliff:g> зможе транслювати аудіо на пристрій \"<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>\", поки ви не скасуєте цей дозвіл."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені пристрою \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запитує дозвіл на трансляцію аудіо й системних функцій між вашими пристроями."</string> <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string> <string name="summary_generic" msgid="1761976003668044801">"Цей додаток зможе синхронізувати інформацію (наприклад, ім’я абонента, який викликає) між телефоном і вибраним пристроєм"</string> <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index 24fd82795dbb..cb1a5278dfc1 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی ایپس کو <xliff:g id="DEVICE_NAME">%3$s</xliff:g> پر سلسلہ بندی کرنے کی اجازت دیں؟"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، ادائیگی کی معلومات، پاس ورڈز اور پیغامات۔<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> پر اس وقت تک ایپس کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> سے ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"اپنے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> اور <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> کے درمیان آڈیو اور سسٹم کی خصوصیات کی سلسلہ بندی کرنے کی <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں؟"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> کو آپ کے <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> پر چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی۔<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> پر اس وقت تک آڈیو کی سلسلہ بندی کر سکے گی جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان آڈیو اور سسٹم کی خصوصیات کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے۔"</string> <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string> <string name="summary_generic" msgid="1761976003668044801">"یہ ایپ آپ کے فون اور منتخب کردہ آلے کے درمیان معلومات، جیسے کسی کال کرنے والے کے نام، کی مطابقت پذیری کر سکے گی"</string> <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index 3335551341bd..993c50226103 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>dagi ilovalarni <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> qurilmasiga striming qilishiga ruxsat berasizmi?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>da koʻrinadigan yoki ijro etiladigan hamma narsaga, jumladan, audio, rasmlar, parollar va xabarlarga kirish huquqini oladi.<br/><br/>Bu ruxsatni olib tashlamaguningizcha, <xliff:g id="APP_NAME_2">%1$s</xliff:g> ilovalarni <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> qurilmasiga striming qila oladi."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> orqali ilovalarni uzatish uchun ruxsat olmoqchi"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Siz <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> va <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> qurilmalari orasida audio striming qilish va tizim funksiyalariga ruxsat berasizmi?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> qurilmangizda ijro etiladigan hamma narsaga kira oladi.<br/><br/>Bu ruxsatni olib tashlamaguningizcha <xliff:g id="APP_NAME_2">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> qurilmasiga audio striming qila oladi."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> audio striming va qurilmalaringiz orasidagi tizim funksiyalari uchun <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nomidan ruxsat soʻramoqda."</string> <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string> <string name="summary_generic" msgid="1761976003668044801">"Bu ilova telefoningiz va tanlangan qurilmada chaqiruvchining ismi kabi maʼlumotlarni sinxronlay oladi"</string> <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index 7f6d5b199d3a..dee65de16b73 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truyền trực tuyến các ứng dụng trên <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> của bạn đến <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung hiển thị hoặc phát trên <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, bao gồm cả âm thanh, ảnh, thông tin thanh toán, mật khẩu và tin nhắn.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sẽ có thể truyền trực tuyến các ứng dụng đến <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truyền trực tuyến các ứng dụng từ <xliff:g id="DEVICE_TYPE">%3$s</xliff:g> của bạn"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truyền trực tuyến âm thanh và các tính năng của hệ thống giữa <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> và <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> sẽ có quyền truy cập vào mọi nội dung được phát trên <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> của bạn.<br/><br/><xliff:g id="APP_NAME_2">%1$s</xliff:g> sẽ có thể truyền trực tuyến âm thanh đến <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> cho đến khi bạn thu hồi quyền này."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_NAME">%2$s</xliff:g> để truyền trực tuyến âm thanh và những tính năng khác của hệ thống giữa các thiết bị của bạn."</string> <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string> <string name="summary_generic" msgid="1761976003668044801">"Ứng dụng này sẽ đồng bộ hoá thông tin (ví dụ: tên người gọi) giữa điện thoại của bạn và thiết bị bạn chọn"</string> <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index c54c452d9d0f..605cab7185d8 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>将您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>上的应用流式传输到<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>吗?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能够访问“<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>”上显示或播放的任何内容,包括音频、照片、付款信息、密码和消息。<br/><br/>“<xliff:g id="APP_NAME_2">%1$s</xliff:g>”可将应用流式传输到“<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>”,除非您撤消此访问权限。"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求获得从您的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>流式传输应用的权限"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"要允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>在<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>和<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>之间流式传输音频和系统功能吗?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"“<xliff:g id="APP_NAME_0">%1$s</xliff:g>”将能够访问“<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>”上播放的任何内容。<br/><br/>“<xliff:g id="APP_NAME_2">%1$s</xliff:g>”能够将音频流式传输到“<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>”,除非您撤消此访问权限。"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表“<xliff:g id="DEVICE_NAME">%2$s</xliff:g>”请求在设备之间流式传输音频和系统功能。"</string> <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string> <string name="summary_generic" msgid="1761976003668044801">"此应用将能在您的手机和所选设备之间同步信息,例如来电者的姓名"</string> <string name="consent_yes" msgid="8344487259618762872">"允许"</string> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index e47dfa005713..d1c73e538981 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」串流<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>應用程式內容至 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 嗎?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取「<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>」上顯示或播放的任何內容,包括音訊、相片、付款資料、密碼和訊息。<br/><br/>「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」將能串流應用程式內容至 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>,直至你移除此存取權限為止。"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求權限,以便從你的<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流應用程式內容"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在你的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>和 <xliff:g id="DEVICE_NAME">%3$s</xliff:g> 之間串流音訊和系統功能嗎<strong></strong>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將能存取 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> 上播放的任何內容。<br/><br/>「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」將能串流音訊至「<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>」,直至你移除此存取權限為止。"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求權限,以便在裝置之間串流音訊和系統功能。"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="summary_generic" msgid="1761976003668044801">"此應用程式將可同步手機和所選裝置的資訊,例如來電者的名稱"</string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index b91024a66cce..c675fedb1dbd 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>將<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>的應用程式串流傳輸到 <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> 嗎?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取 <xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> 顯示或播放的所有內容,包括音訊、相片、付款資訊、密碼和訊息。<br/><br/>「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」可將應用程式串流傳輸到 <xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>,直到你移除這個權限為止。"</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> 要求必要權限,以便從<xliff:g id="DEVICE_TYPE">%3$s</xliff:g>串流傳輸應用程式"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>和「<xliff:g id="DEVICE_NAME">%3$s</xliff:g>」<strong></strong>間串流傳輸音訊和系統功能嗎?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」將可存取「<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>」播放的所有內容。<br/><br/>「<xliff:g id="APP_NAME_2">%1$s</xliff:g>」可將音訊串流傳輸到「<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g>」,直到你移除這個權限為止。"</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」要求必要權限,以便在裝置間串流傳輸音訊和系統功能。"</string> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="summary_generic" msgid="1761976003668044801">"這個應用程式將可在手機和指定裝置間同步資訊,例如來電者名稱"</string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index 160332e77c94..365b2f4753d0 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -36,6 +36,9 @@ <string name="title_nearby_device_streaming" msgid="2727103756701741359">"Vumela <strong>i-<xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuze isakaze ama-app e-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho <strong>ku-<xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>?"</string> <string name="summary_nearby_device_streaming" msgid="70434958004946884">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini ebonakalayo noma edlalwayo ku-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g>, okuhlanganisa umsindo, izithombe, ulwazi lokukhokha, amaphasiwedi, nemilayezo.<br/><br/>I-<xliff:g id="APP_NAME_2">%1$s</xliff:g> izokwazi ukusakaza ama-app ku-<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string> <string name="helper_summary_nearby_device_streaming" msgid="4712712177819370967">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukuze isakaze ama-app nezakhi ukusuka ku-<xliff:g id="DEVICE_TYPE">%3$s</xliff:g> yakho"</string> + <string name="title_sensor_device_streaming" msgid="2395553261097861497">"Uvumela i-<xliff:g id="APP_NAME">%1$s</xliff:g> ukuthi isakaze izakhi zomsindo nesistimu phakathi kwe-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ne-<xliff:g id="DEVICE_NAME">%3$s</xliff:g>?"</string> + <string name="summary_sensor_device_streaming" msgid="3413105061195145547">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> izokwazi ukufinyelela kunoma yini edlalwa ku-<xliff:g id="DEVICE_NAME_1">%3$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%1$s</xliff:g> yakho futhi izokwazi ukusakaza umsindo ku-<xliff:g id="DEVICE_NAME_3">%3$s</xliff:g> uze ususe ukufinyelela kule mvume."</string> + <string name="helper_summary_sensor_device_streaming" msgid="8860174545653786353">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> ukuze isakaze izakhi zomsindo nesistimu phakathi kwamadivayisi akho."</string> <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string> <string name="summary_generic" msgid="1761976003668044801">"Le app izokwazi ukuvumelanisa ulwazi, njengegama lomuntu othile ofonayo, phakathi kwefoni yakho nedivayisi ekhethiwe"</string> <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string> diff --git a/packages/CrashRecovery/framework/api/system-current.txt b/packages/CrashRecovery/framework/api/system-current.txt index 68429ea4297d..ad17ec69f168 100644 --- a/packages/CrashRecovery/framework/api/system-current.txt +++ b/packages/CrashRecovery/framework/api/system-current.txt @@ -9,7 +9,7 @@ package android.service.watchdog { method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages(); method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages(); method public abstract void onRequestHealthCheck(@NonNull String); - method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public final void setHealthCheckResultCallback(@Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<android.os.Bundle>); + method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public final void setHealthCheckPassedCallback(@Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<android.os.Bundle>); field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"; field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE = "android.service.watchdog.extra.HEALTH_CHECK_PASSED_PACKAGE"; field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService"; diff --git a/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java b/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java index b03e37600bbb..fdb0fc538fdf 100644 --- a/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java +++ b/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java @@ -180,7 +180,7 @@ public abstract class ExplicitHealthCheckService extends Service { * passed the health check. */ @FlaggedApi(Flags.FLAG_ENABLE_CRASHRECOVERY) - public final void setHealthCheckResultCallback(@CallbackExecutor @Nullable Executor executor, + public final void setHealthCheckPassedCallback(@CallbackExecutor @Nullable Executor executor, @Nullable Consumer<Bundle> callback) { mCallbackExecutor = executor; mHealthCheckResultCallback = callback; diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java index 31e1eb36ad8d..ef46906f9cf4 100644 --- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java +++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java @@ -347,8 +347,8 @@ public class PackageWatchdog { * and boot loops. * @param executor Executor for the thread on which observers would receive callbacks */ - public void registerHealthObserver(@NonNull PackageHealthObserver observer, - @NonNull @CallbackExecutor Executor executor) { + public void registerHealthObserver(@NonNull @CallbackExecutor Executor executor, + @NonNull PackageHealthObserver observer) { synchronized (sLock) { ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier()); if (internalObserver != null) { @@ -390,8 +390,8 @@ public class PackageWatchdog { * * @throws IllegalStateException if the observer was not previously registered */ - public void startExplicitHealthCheck(@NonNull PackageHealthObserver observer, - @NonNull List<String> packageNames, long timeoutMs) { + public void startExplicitHealthCheck(@NonNull List<String> packageNames, long timeoutMs, + @NonNull PackageHealthObserver observer) { synchronized (sLock) { if (!mAllObservers.containsKey(observer.getUniqueIdentifier())) { Slog.wtf(TAG, "No observer found, need to register the observer: " @@ -767,14 +767,6 @@ public class PackageWatchdog { } /** - * Indicates that the result of a mitigation executed during - * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or - * {@link PackageHealthObserver#onExecuteBootLoopMitigation} is unknown. - */ - public static final int MITIGATION_RESULT_UNKNOWN = - ObserverMitigationResult.MITIGATION_RESULT_UNKNOWN; - - /** * Indicates that a mitigation was successfully triggered or executed during * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or * {@link PackageHealthObserver#onExecuteBootLoopMitigation}. @@ -790,23 +782,6 @@ public class PackageWatchdog { public static final int MITIGATION_RESULT_SKIPPED = ObserverMitigationResult.MITIGATION_RESULT_SKIPPED; - /** - * Indicates that a mitigation executed during - * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or - * {@link PackageHealthObserver#onExecuteBootLoopMitigation} failed, - * but the failure is potentially retryable. - */ - public static final int MITIGATION_RESULT_FAILURE_RETRYABLE = - ObserverMitigationResult.MITIGATION_RESULT_FAILURE_RETRYABLE; - - /** - * Indicates that a mitigation executed during - * {@link PackageHealthObserver#onExecuteHealthCheckMitigation} or - * {@link PackageHealthObserver#onExecuteBootLoopMitigation} failed, - * and the failure is not retryable. - */ - public static final int MITIGATION_RESULT_FAILURE_NON_RETRYABLE = - ObserverMitigationResult.MITIGATION_RESULT_FAILURE_NON_RETRYABLE; /** * Possible return values of the for mitigations executed during @@ -816,18 +791,12 @@ public class PackageWatchdog { */ @Retention(SOURCE) @IntDef(prefix = "MITIGATION_RESULT_", value = { - ObserverMitigationResult.MITIGATION_RESULT_UNKNOWN, ObserverMitigationResult.MITIGATION_RESULT_SUCCESS, ObserverMitigationResult.MITIGATION_RESULT_SKIPPED, - ObserverMitigationResult.MITIGATION_RESULT_FAILURE_RETRYABLE, - ObserverMitigationResult.MITIGATION_RESULT_FAILURE_NON_RETRYABLE, }) public @interface ObserverMitigationResult { - int MITIGATION_RESULT_UNKNOWN = 0; int MITIGATION_RESULT_SUCCESS = 1; int MITIGATION_RESULT_SKIPPED = 2; - int MITIGATION_RESULT_FAILURE_RETRYABLE = 3; - int MITIGATION_RESULT_FAILURE_NON_RETRYABLE = 4; } /** @@ -921,11 +890,6 @@ public class PackageWatchdog { * @param mitigationCount the number of times mitigation has been called for this package * (including this time). * @return {@link #MITIGATION_RESULT_SUCCESS} if the mitigation was successful, - * {@link #MITIGATION_RESULT_FAILURE_RETRYABLE} if the mitigation failed but can be - * retried, - * {@link #MITIGATION_RESULT_FAILURE_NON_RETRYABLE} if the mitigation failed and - * cannot be retried, - * {@link #MITIGATION_RESULT_UNKNOWN} if the result of the mitigation is unknown, * or {@link #MITIGATION_RESULT_SKIPPED} if the mitigation was skipped. */ @ObserverMitigationResult int onExecuteHealthCheckMitigation( @@ -957,11 +921,6 @@ public class PackageWatchdog { * boot loop (including this time). * * @return {@link #MITIGATION_RESULT_SUCCESS} if the mitigation was successful, - * {@link #MITIGATION_RESULT_FAILURE_RETRYABLE} if the mitigation failed but can be - * retried, - * {@link #MITIGATION_RESULT_FAILURE_NON_RETRYABLE} if the mitigation failed and - * cannot be retried, - * {@link #MITIGATION_RESULT_UNKNOWN} if the result of the mitigation is unknown, * or {@link #MITIGATION_RESULT_SKIPPED} if the mitigation was skipped. */ default @ObserverMitigationResult int onExecuteBootLoopMitigation(int mitigationCount) { @@ -2074,15 +2033,19 @@ public class PackageWatchdog { bootMitigationCounts.put(observer.name, observer.getBootMitigationCount()); } + FileOutputStream fileStream = null; + ObjectOutputStream objectStream = null; try { - FileOutputStream fileStream = new FileOutputStream(new File(filePath)); - ObjectOutputStream objectStream = new ObjectOutputStream(fileStream); + fileStream = new FileOutputStream(new File(filePath)); + objectStream = new ObjectOutputStream(fileStream); objectStream.writeObject(bootMitigationCounts); objectStream.flush(); - objectStream.close(); - fileStream.close(); } catch (Exception e) { Slog.i(TAG, "Could not save observers metadata to file: " + e); + return; + } finally { + IoUtils.closeQuietly(objectStream); + IoUtils.closeQuietly(fileStream); } } @@ -2233,23 +2196,32 @@ public class PackageWatchdog { void readAllObserversBootMitigationCountIfNecessary(String filePath) { File metadataFile = new File(filePath); if (metadataFile.exists()) { + FileInputStream fileStream = null; + ObjectInputStream objectStream = null; + HashMap<String, Integer> bootMitigationCounts = null; try { - FileInputStream fileStream = new FileInputStream(metadataFile); - ObjectInputStream objectStream = new ObjectInputStream(fileStream); - HashMap<String, Integer> bootMitigationCounts = + fileStream = new FileInputStream(metadataFile); + objectStream = new ObjectInputStream(fileStream); + bootMitigationCounts = (HashMap<String, Integer>) objectStream.readObject(); - objectStream.close(); - fileStream.close(); - - for (int i = 0; i < mAllObservers.size(); i++) { - final ObserverInternal observer = mAllObservers.valueAt(i); - if (bootMitigationCounts.containsKey(observer.name)) { - observer.setBootMitigationCount( - bootMitigationCounts.get(observer.name)); - } - } } catch (Exception e) { Slog.i(TAG, "Could not read observer metadata file: " + e); + return; + } finally { + IoUtils.closeQuietly(objectStream); + IoUtils.closeQuietly(fileStream); + } + + if (bootMitigationCounts == null || bootMitigationCounts.isEmpty()) { + Slog.i(TAG, "No observer in metadata file"); + return; + } + for (int i = 0; i < mAllObservers.size(); i++) { + final ObserverInternal observer = mAllObservers.valueAt(i); + if (bootMitigationCounts.containsKey(observer.name)) { + observer.setBootMitigationCount( + bootMitigationCounts.get(observer.name)); + } } } } diff --git a/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java index bb9e96238e1c..40bc5f78a9c6 100644 --- a/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java +++ b/packages/CrashRecovery/services/module/java/com/android/server/RescueParty.java @@ -162,7 +162,7 @@ public class RescueParty { /** Register the Rescue Party observer as a Package Watchdog health observer */ public static void registerHealthObserver(Context context) { PackageWatchdog.getInstance(context).registerHealthObserver( - RescuePartyObserver.getInstance(context), context.getMainExecutor()); + context.getMainExecutor(), RescuePartyObserver.getInstance(context)); } private static boolean isDisabled() { @@ -316,9 +316,9 @@ public class RescueParty { Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: " + updatedNamespace); PackageWatchdog.getInstance(context).startExplicitHealthCheck( - rescuePartyObserver, callingPackageList, - DEFAULT_OBSERVING_DURATION_MS); + DEFAULT_OBSERVING_DURATION_MS, + rescuePartyObserver); } } diff --git a/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java index c75f3aa60ac4..4978df491c62 100644 --- a/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/packages/CrashRecovery/services/module/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -113,8 +113,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve dataDir.mkdirs(); mLastStagedRollbackIdsFile = new File(dataDir, "last-staged-rollback-ids"); mTwoPhaseRollbackEnabledFile = new File(dataDir, "two-phase-rollback-enabled"); - PackageWatchdog.getInstance(mContext).registerHealthObserver(this, - context.getMainExecutor()); + PackageWatchdog.getInstance(mContext).registerHealthObserver(context.getMainExecutor(), + this); if (SystemProperties.getBoolean("sys.boot_completed", false)) { // Load the value from the file if system server has crashed and restarted diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java index ffae5176cebf..4a00ed3d1d46 100644 --- a/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java +++ b/packages/CrashRecovery/services/platform/java/com/android/server/PackageWatchdog.java @@ -363,7 +363,7 @@ public class PackageWatchdog { * it will resume observing any packages requested from a previous boot. * @hide */ - public void registerHealthObserver(PackageHealthObserver observer, Executor ignoredExecutor) { + public void registerHealthObserver(Executor ignoredExecutor, PackageHealthObserver observer) { synchronized (mLock) { ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier()); if (internalObserver != null) { @@ -397,8 +397,8 @@ public class PackageWatchdog { * {@link #DEFAULT_OBSERVING_DURATION_MS} will be used. * @hide */ - public void startExplicitHealthCheck(PackageHealthObserver observer, List<String> packageNames, - long durationMs) { + public void startExplicitHealthCheck(List<String> packageNames, long durationMs, + PackageHealthObserver observer) { if (packageNames.isEmpty()) { Slog.wtf(TAG, "No packages to observe, " + observer.getUniqueIdentifier()); return; @@ -446,7 +446,7 @@ public class PackageWatchdog { } // Register observer in case not already registered - registerHealthObserver(observer, null); + registerHealthObserver(null, observer); // Sync after we add the new packages to the observers. We may have received packges // requiring an earlier schedule than we are currently scheduled for. @@ -2021,15 +2021,19 @@ public class PackageWatchdog { bootMitigationCounts.put(observer.name, observer.getBootMitigationCount()); } + FileOutputStream fileStream = null; + ObjectOutputStream objectStream = null; try { - FileOutputStream fileStream = new FileOutputStream(new File(filePath)); - ObjectOutputStream objectStream = new ObjectOutputStream(fileStream); + fileStream = new FileOutputStream(new File(filePath)); + objectStream = new ObjectOutputStream(fileStream); objectStream.writeObject(bootMitigationCounts); objectStream.flush(); - objectStream.close(); - fileStream.close(); } catch (Exception e) { Slog.i(TAG, "Could not save observers metadata to file: " + e); + return; + } finally { + IoUtils.closeQuietly(objectStream); + IoUtils.closeQuietly(fileStream); } } @@ -2180,23 +2184,32 @@ public class PackageWatchdog { void readAllObserversBootMitigationCountIfNecessary(String filePath) { File metadataFile = new File(filePath); if (metadataFile.exists()) { + FileInputStream fileStream = null; + ObjectInputStream objectStream = null; + HashMap<String, Integer> bootMitigationCounts = null; try { - FileInputStream fileStream = new FileInputStream(metadataFile); - ObjectInputStream objectStream = new ObjectInputStream(fileStream); - HashMap<String, Integer> bootMitigationCounts = + fileStream = new FileInputStream(metadataFile); + objectStream = new ObjectInputStream(fileStream); + bootMitigationCounts = (HashMap<String, Integer>) objectStream.readObject(); - objectStream.close(); - fileStream.close(); - - for (int i = 0; i < mAllObservers.size(); i++) { - final ObserverInternal observer = mAllObservers.valueAt(i); - if (bootMitigationCounts.containsKey(observer.name)) { - observer.setBootMitigationCount( - bootMitigationCounts.get(observer.name)); - } - } } catch (Exception e) { Slog.i(TAG, "Could not read observer metadata file: " + e); + return; + } finally { + IoUtils.closeQuietly(objectStream); + IoUtils.closeQuietly(fileStream); + } + + if (bootMitigationCounts == null || bootMitigationCounts.isEmpty()) { + Slog.i(TAG, "No observer in metadata file"); + return; + } + for (int i = 0; i < mAllObservers.size(); i++) { + final ObserverInternal observer = mAllObservers.valueAt(i); + if (bootMitigationCounts.containsKey(observer.name)) { + observer.setBootMitigationCount( + bootMitigationCounts.get(observer.name)); + } } } } diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java index c6452d31f881..8251fb4c98e4 100644 --- a/packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java +++ b/packages/CrashRecovery/services/platform/java/com/android/server/RescueParty.java @@ -168,7 +168,7 @@ public class RescueParty { /** Register the Rescue Party observer as a Package Watchdog health observer */ public static void registerHealthObserver(Context context) { PackageWatchdog.getInstance(context).registerHealthObserver( - RescuePartyObserver.getInstance(context), null); + null, RescuePartyObserver.getInstance(context)); } private static boolean isDisabled() { @@ -390,9 +390,9 @@ public class RescueParty { Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: " + updatedNamespace); PackageWatchdog.getInstance(context).startExplicitHealthCheck( - rescuePartyObserver, callingPackageList, - DEFAULT_OBSERVING_DURATION_MS); + DEFAULT_OBSERVING_DURATION_MS, + rescuePartyObserver); } } diff --git a/packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 04115373e926..5c4e57e93519 100644 --- a/packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/packages/CrashRecovery/services/platform/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -112,7 +112,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve dataDir.mkdirs(); mLastStagedRollbackIdsFile = new File(dataDir, "last-staged-rollback-ids"); mTwoPhaseRollbackEnabledFile = new File(dataDir, "two-phase-rollback-enabled"); - PackageWatchdog.getInstance(mContext).registerHealthObserver(this, null); + PackageWatchdog.getInstance(mContext).registerHealthObserver(null, this); mApexManager = apexManager; if (SystemProperties.getBoolean("sys.boot_completed", false)) { @@ -286,7 +286,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @AnyThread @NonNull public void startObservingHealth(@NonNull List<String> packages, @NonNull long durationMs) { - PackageWatchdog.getInstance(mContext).startExplicitHealthCheck(this, packages, durationMs); + PackageWatchdog.getInstance(mContext).startExplicitHealthCheck(packages, durationMs, this); } @AnyThread diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index e029f3a16066..4da73593bdea 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" /> <uses-permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER" /> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" /> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index 635ae20cfa38..6c06fab16502 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -26,6 +26,7 @@ import android.app.admin.DevicePolicyManager; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; @@ -274,8 +275,20 @@ public class InstallStart extends Activity { } private boolean canPackageQuery(int callingUid, Uri packageUri) { - ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(), - PackageManager.ComponentInfoFlags.of(0)); + ProviderInfo info; + try { + if (Flags.uidBasedProviderLookup()) { + info = mPackageManager.resolveContentProviderForUid(packageUri.getAuthority(), + PackageManager.ComponentInfoFlags.of(0), callingUid); + } else { + info = mPackageManager.resolveContentProvider(packageUri.getAuthority(), + PackageManager.ComponentInfoFlags.of(0)); + } + } catch (Exception e) { + Log.e(TAG, "Caller cannot access " + packageUri, e); + return false; + } + if (info == null) { return false; } diff --git a/packages/SettingsLib/ButtonPreference/Android.bp b/packages/SettingsLib/ButtonPreference/Android.bp index 0382829b2652..08dd27fd25ce 100644 --- a/packages/SettingsLib/ButtonPreference/Android.bp +++ b/packages/SettingsLib/ButtonPreference/Android.bp @@ -24,4 +24,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.healthfitness", + ], } diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java index 993555e78bea..be711accd542 100644 --- a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java +++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java @@ -247,4 +247,28 @@ public class ButtonPreference extends Preference implements GroupSectionDividerM mButton.setLayoutParams(lp); } } + + /** + * Sets the style of the button. + * + * @param type Specifies the button's type, which sets the attribute `buttonPreferenceType`. + * Possible values are: + * <ul> + * <li>0: filled</li> + * <li>1: tonal</li> + * <li>2: outline</li> + * </ul> + * @param size Specifies the button's size, which sets the attribute `buttonPreferenceSize`. + * Possible values are: + * <ul> + * <li>0: normal</li> + * <li>1: large</li> + * <li>2: extra large</li> + * </ul> + */ + public void setButtonStyle(int type, int size) { + int layoutId = ButtonStyle.getLayoutId(type, size); + setLayoutResource(layoutId); + notifyChanged(); + } } diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt index 53507fe46d1f..8335ee43df26 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt @@ -16,6 +16,7 @@ package com.android.settingslib.datastore +import android.Manifest import android.content.ContentResolver import android.content.Context import android.net.Uri @@ -82,5 +83,11 @@ class SettingsGlobalStore private constructor(contentResolver: ContentResolver) instance = it } } + + /** Returns the required permissions to read [Global] settings. */ + fun getReadPermissions() = arrayOf<String>() + + /** Returns the required permissions to write [Global] settings. */ + fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SECURE_SETTINGS) } } diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt index ca7fd7bb5f1e..c117b926d1eb 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt @@ -16,6 +16,7 @@ package com.android.settingslib.datastore +import android.Manifest import android.content.ContentResolver import android.content.Context import android.net.Uri @@ -82,5 +83,11 @@ class SettingsSecureStore private constructor(contentResolver: ContentResolver) instance = it } } + + /** Returns the required permissions to read [Secure] settings. */ + fun getReadPermissions() = arrayOf<String>() + + /** Returns the required permissions to write [Secure] settings. */ + fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SECURE_SETTINGS) } } diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt index 20a74d3b4a81..f5a2f940bc03 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt @@ -16,6 +16,7 @@ package com.android.settingslib.datastore +import android.Manifest import android.content.ContentResolver import android.content.Context import android.net.Uri @@ -82,5 +83,11 @@ class SettingsSystemStore private constructor(contentResolver: ContentResolver) instance = it } } + + /** Returns the required permissions to read [System] settings. */ + fun getReadPermissions() = arrayOf<String>() + + /** Returns the required permissions to write [System] settings. */ + fun getWritePermissions() = arrayOf(Manifest.permission.WRITE_SETTINGS) } } diff --git a/packages/SettingsLib/Graph/graph.proto b/packages/SettingsLib/Graph/graph.proto index f611793b619b..2aa619aa67f9 100644 --- a/packages/SettingsLib/Graph/graph.proto +++ b/packages/SettingsLib/Graph/graph.proto @@ -81,6 +81,10 @@ message PreferenceProto { optional PreferenceValueDescriptorProto value_descriptor = 15; // Indicate how sensitive of the preference. optional int32 sensitivity_level = 16; + // The required permissions to read preference value. + repeated string read_permissions = 17; + // The required permissions to write preference value. + repeated string write_permissions = 18; // Target of an Intent message ActionTarget { @@ -108,6 +112,7 @@ message PreferenceValueProto { oneof value { bool boolean_value = 1; int32 int_value = 2; + float float_value = 3; } } @@ -116,6 +121,7 @@ message PreferenceValueDescriptorProto { oneof type { bool boolean_type = 1; RangeValueProto range_value = 2; + bool float_type = 3; } } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt index eaa79266b194..91dec03bf2af 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt @@ -42,6 +42,7 @@ import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget import com.android.settingslib.graph.proto.PreferenceScreenProto import com.android.settingslib.graph.proto.TextProto import com.android.settingslib.metadata.BooleanValue +import com.android.settingslib.metadata.FloatPersistentPreference import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceHierarchy @@ -390,7 +391,13 @@ fun PreferenceMetadata.toProto( } persistent = metadata.isPersistent(context) if (persistent) { - if (metadata is PersistentPreference<*>) sensitivityLevel = metadata.sensitivityLevel + if (metadata is PersistentPreference<*>) { + sensitivityLevel = metadata.sensitivityLevel + val readPermissions = metadata.getReadPermissions(context) + readPermissions.forEach { addReadPermissions(it) } + val writePermissions = metadata.getWritePermissions(context) + writePermissions.forEach { addWritePermissions(it) } + } if ( flags.includeValue() && enabled && @@ -399,15 +406,13 @@ fun PreferenceMetadata.toProto( metadata is PersistentPreference<*> && metadata.evalReadPermit(context, callingPid, callingUid) == ReadWritePermit.ALLOW ) { + val storage = metadata.storage(context) value = preferenceValueProto { when (metadata) { - is BooleanValue -> - metadata.storage(context).getBoolean(metadata.key)?.let { - booleanValue = it - } - is RangeValue -> { - metadata.storage(context).getInt(metadata.key)?.let { intValue = it } - } + is BooleanValue -> storage.getBoolean(metadata.key)?.let { booleanValue = it } + is RangeValue -> storage.getInt(metadata.key)?.let { intValue = it } + is FloatPersistentPreference -> + storage.getFloat(metadata.key)?.let { floatValue = it } else -> {} } } @@ -421,6 +426,7 @@ fun PreferenceMetadata.toProto( max = metadata.getMaxValue(context) step = metadata.getIncrementStep(context) } + is FloatPersistentPreference -> floatType = true else -> {} } } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt index d72ba0805db3..83c430488317 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt @@ -159,6 +159,12 @@ class PreferenceSetterApiHandler( } storage.setInt(key, intValue) return PreferenceSetterResult.OK + } else if (value.hasFloatValue()) { + val floatValue = value.floatValue + val resultCode = metadata.checkWritePermit(floatValue) + if (resultCode != PreferenceSetterResult.OK) return resultCode + storage.setFloat(key, floatValue) + return PreferenceSetterResult.OK } } catch (e: Exception) { return PreferenceSetterResult.INTERNAL_ERROR diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt index dee32d9ed80e..adbe77318353 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt @@ -35,8 +35,9 @@ val PreferenceScreenProto.rootOrNull /** Kotlin DSL-style builder for [PreferenceScreenProto]. */ @JvmSynthetic -inline fun preferenceScreenProto(init: PreferenceScreenProto.Builder.() -> Unit) = - PreferenceScreenProto.newBuilder().also(init).build() +inline fun preferenceScreenProto( + init: PreferenceScreenProto.Builder.() -> Unit +): PreferenceScreenProto = PreferenceScreenProto.newBuilder().also(init).build() /** Returns preference or null. */ val PreferenceOrGroupProto.preferenceOrNull @@ -48,8 +49,9 @@ val PreferenceOrGroupProto.groupOrNull /** Kotlin DSL-style builder for [PreferenceOrGroupProto]. */ @JvmSynthetic -inline fun preferenceOrGroupProto(init: PreferenceOrGroupProto.Builder.() -> Unit) = - PreferenceOrGroupProto.newBuilder().also(init).build() +inline fun preferenceOrGroupProto( + init: PreferenceOrGroupProto.Builder.() -> Unit +): PreferenceOrGroupProto = PreferenceOrGroupProto.newBuilder().also(init).build() /** Returns preference or null. */ val PreferenceGroupProto.preferenceOrNull @@ -57,8 +59,9 @@ val PreferenceGroupProto.preferenceOrNull /** Kotlin DSL-style builder for [PreferenceGroupProto]. */ @JvmSynthetic -inline fun preferenceGroupProto(init: PreferenceGroupProto.Builder.() -> Unit) = - PreferenceGroupProto.newBuilder().also(init).build() +inline fun preferenceGroupProto( + init: PreferenceGroupProto.Builder.() -> Unit +): PreferenceGroupProto = PreferenceGroupProto.newBuilder().also(init).build() /** Returns title or null. */ val PreferenceProto.titleOrNull @@ -74,7 +77,7 @@ val PreferenceProto.actionTargetOrNull /** Kotlin DSL-style builder for [PreferenceProto]. */ @JvmSynthetic -inline fun preferenceProto(init: PreferenceProto.Builder.() -> Unit) = +inline fun preferenceProto(init: PreferenceProto.Builder.() -> Unit): PreferenceProto = PreferenceProto.newBuilder().also(init).build() /** Returns intent or null. */ @@ -83,39 +86,42 @@ val ActionTarget.intentOrNull /** Kotlin DSL-style builder for [ActionTarget]. */ @JvmSynthetic -inline fun actionTargetProto(init: ActionTarget.Builder.() -> Unit) = +inline fun actionTargetProto(init: ActionTarget.Builder.() -> Unit): ActionTarget = ActionTarget.newBuilder().also(init).build() /** Kotlin DSL-style builder for [PreferenceValueProto]. */ @JvmSynthetic -inline fun preferenceValueProto(init: PreferenceValueProto.Builder.() -> Unit) = - PreferenceValueProto.newBuilder().also(init).build() +inline fun preferenceValueProto( + init: PreferenceValueProto.Builder.() -> Unit +): PreferenceValueProto = PreferenceValueProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [PreferenceValueDescriptorProto]. */ @JvmSynthetic -inline fun preferenceValueDescriptorProto(init: PreferenceValueDescriptorProto.Builder.() -> Unit) = - PreferenceValueDescriptorProto.newBuilder().also(init).build() +inline fun preferenceValueDescriptorProto( + init: PreferenceValueDescriptorProto.Builder.() -> Unit +): PreferenceValueDescriptorProto = PreferenceValueDescriptorProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [RangeValueProto]. */ @JvmSynthetic -inline fun rangeValueProto(init: RangeValueProto.Builder.() -> Unit) = +inline fun rangeValueProto(init: RangeValueProto.Builder.() -> Unit): RangeValueProto = RangeValueProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [TextProto]. */ @JvmSynthetic -inline fun textProto(init: TextProto.Builder.() -> Unit) = TextProto.newBuilder().also(init).build() +inline fun textProto(init: TextProto.Builder.() -> Unit): TextProto = + TextProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [IntentProto]. */ @JvmSynthetic -inline fun intentProto(init: IntentProto.Builder.() -> Unit) = +inline fun intentProto(init: IntentProto.Builder.() -> Unit): IntentProto = IntentProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [BundleProto]. */ @JvmSynthetic -inline fun bundleProto(init: BundleProto.Builder.() -> Unit) = +inline fun bundleProto(init: BundleProto.Builder.() -> Unit): BundleProto = BundleProto.newBuilder().also(init).build() /** Kotlin DSL-style builder for [BundleValue]. */ @JvmSynthetic -inline fun bundleValueProto(init: BundleValue.Builder.() -> Unit) = +inline fun bundleValueProto(init: BundleValue.Builder.() -> Unit): BundleValue = BundleValue.newBuilder().also(init).build() diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java index adc4f316aca9..bc4f1f942dc0 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java @@ -167,6 +167,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi if (mLottieDynamicColor) { LottieColorUtils.applyDynamicColors(getContext(), illustrationView); } + LottieColorUtils.applyMaterialColor(getContext(), illustrationView); if (mOnBindListener != null) { mOnBindListener.onBind(illustrationView); diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java index 98a72909b276..4421424c0e39 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java @@ -21,14 +21,14 @@ import android.content.res.Configuration; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import com.android.settingslib.color.R; +import androidx.annotation.NonNull; + +import com.android.settingslib.widget.theme.R; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieProperty; import com.airbnb.lottie.model.KeyPath; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** @@ -37,52 +37,97 @@ import java.util.Map; */ public class LottieColorUtils { private static final Map<String, Integer> DARK_TO_LIGHT_THEME_COLOR_MAP; + private static final Map<String, Integer> MATERIAL_COLOR_MAP; static { - HashMap<String, Integer> map = new HashMap<>(); - map.put( - ".grey200", - R.color.settingslib_color_grey800); - map.put( - ".grey600", - R.color.settingslib_color_grey400); - map.put( - ".grey800", - R.color.settingslib_color_grey300); - map.put( - ".grey900", - R.color.settingslib_color_grey50); - map.put( - ".red100", - R.color.settingslib_color_red500); - map.put( - ".red200", - R.color.settingslib_color_red500); - map.put( - ".red400", - R.color.settingslib_color_red600); - map.put( - ".black", - android.R.color.white); - map.put( - ".blue200", - R.color.settingslib_color_blue700); - map.put( - ".blue400", - R.color.settingslib_color_blue600); - map.put( - ".green100", - R.color.settingslib_color_green500); - map.put( - ".green200", - R.color.settingslib_color_green500); - map.put( - ".green400", - R.color.settingslib_color_green600); - map.put( - ".cream", - R.color.settingslib_color_charcoal); - DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map); + DARK_TO_LIGHT_THEME_COLOR_MAP = Map.ofEntries( + Map.entry(".grey200", + com.android.settingslib.color.R.color.settingslib_color_grey800), + Map.entry(".grey600", + com.android.settingslib.color.R.color.settingslib_color_grey400), + Map.entry(".grey800", + com.android.settingslib.color.R.color.settingslib_color_grey300), + Map.entry(".grey900", + com.android.settingslib.color.R.color.settingslib_color_grey50), + Map.entry(".red100", + com.android.settingslib.color.R.color.settingslib_color_red500), + Map.entry(".red200", + com.android.settingslib.color.R.color.settingslib_color_red500), + Map.entry(".red400", + com.android.settingslib.color.R.color.settingslib_color_red600), + Map.entry(".black", + android.R.color.white), + Map.entry(".blue200", + com.android.settingslib.color.R.color.settingslib_color_blue700), + Map.entry(".blue400", + com.android.settingslib.color.R.color.settingslib_color_blue600), + Map.entry(".green100", + com.android.settingslib.color.R.color.settingslib_color_green500), + Map.entry(".green200", + com.android.settingslib.color.R.color.settingslib_color_green500), + Map.entry(".green400", + com.android.settingslib.color.R.color.settingslib_color_green600), + Map.entry(".cream", + com.android.settingslib.color.R.color.settingslib_color_charcoal)); + + MATERIAL_COLOR_MAP = Map.ofEntries( + Map.entry(".primary", R.color.settingslib_materialColorPrimary), + Map.entry(".onPrimary", R.color.settingslib_materialColorOnPrimary), + Map.entry(".primaryContainer", R.color.settingslib_materialColorPrimaryContainer), + Map.entry(".onPrimaryContainer", + R.color.settingslib_materialColorOnPrimaryContainer), + Map.entry(".primaryInverse", R.color.settingslib_materialColorPrimaryInverse), + Map.entry(".primaryFixed", R.color.settingslib_materialColorPrimaryFixed), + Map.entry(".primaryFixedDim", R.color.settingslib_materialColorPrimaryFixedDim), + Map.entry(".onPrimaryFixed", R.color.settingslib_materialColorOnPrimaryFixed), + Map.entry(".onPrimaryFixedVariant", + R.color.settingslib_materialColorOnPrimaryFixedVariant), + Map.entry(".secondary", R.color.settingslib_materialColorSecondary), + Map.entry(".onSecondary", R.color.settingslib_materialColorOnSecondary), + Map.entry(".secondaryContainer", + R.color.settingslib_materialColorSecondaryContainer), + Map.entry(".onSecondaryContainer", + R.color.settingslib_materialColorOnSecondaryContainer), + Map.entry(".secondaryFixed", R.color.settingslib_materialColorSecondaryFixed), + Map.entry(".secondaryFixedDim", R.color.settingslib_materialColorSecondaryFixedDim), + Map.entry(".onSecondaryFixed", R.color.settingslib_materialColorOnSecondaryFixed), + Map.entry(".onSecondaryFixedVariant", + R.color.settingslib_materialColorOnSecondaryFixedVariant), + Map.entry(".tertiary", R.color.settingslib_materialColorTertiary), + Map.entry(".onTertiary", R.color.settingslib_materialColorOnTertiary), + Map.entry(".tertiaryContainer", R.color.settingslib_materialColorTertiaryContainer), + Map.entry(".onTertiaryContainer", + R.color.settingslib_materialColorOnTertiaryContainer), + Map.entry(".tertiaryFixed", R.color.settingslib_materialColorTertiaryFixed), + Map.entry(".tertiaryFixedDim", R.color.settingslib_materialColorTertiaryFixedDim), + Map.entry(".onTertiaryFixed", R.color.settingslib_materialColorOnTertiaryFixed), + Map.entry(".onTertiaryFixedVariant", + R.color.settingslib_materialColorOnTertiaryFixedVariant), + Map.entry(".error", R.color.settingslib_materialColorError), + Map.entry(".onError", R.color.settingslib_materialColorOnError), + Map.entry(".errorContainer", R.color.settingslib_materialColorErrorContainer), + Map.entry(".onErrorContainer", R.color.settingslib_materialColorOnErrorContainer), + Map.entry(".outline", R.color.settingslib_materialColorOutline), + Map.entry(".outlineVariant", R.color.settingslib_materialColorOutlineVariant), + Map.entry(".background", R.color.settingslib_materialColorBackground), + Map.entry(".onBackground", R.color.settingslib_materialColorOnBackground), + Map.entry(".surface", R.color.settingslib_materialColorSurface), + Map.entry(".onSurface", R.color.settingslib_materialColorOnSurface), + Map.entry(".surfaceVariant", R.color.settingslib_materialColorSurfaceVariant), + Map.entry(".onSurfaceVariant", R.color.settingslib_materialColorOnSurfaceVariant), + Map.entry(".surfaceInverse", R.color.settingslib_materialColorSurfaceInverse), + Map.entry(".onSurfaceInverse", R.color.settingslib_materialColorOnSurfaceInverse), + Map.entry(".surfaceBright", R.color.settingslib_materialColorSurfaceBright), + Map.entry(".surfaceDim", R.color.settingslib_materialColorSurfaceDim), + Map.entry(".surfaceContainer", R.color.settingslib_materialColorSurfaceContainer), + Map.entry(".surfaceContainerLow", + R.color.settingslib_materialColorSurfaceContainerLow), + Map.entry(".surfaceContainerLowest", + R.color.settingslib_materialColorSurfaceContainerLowest), + Map.entry(".surfaceContainerHigh", + R.color.settingslib_materialColorSurfaceContainerHigh), + Map.entry(".surfaceContainerHighest", + R.color.settingslib_materialColorSurfaceContainerHighest)); } private LottieColorUtils() { @@ -108,4 +153,20 @@ public class LottieColorUtils { frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); } } + + /** Applies material colors. */ + public static void applyMaterialColor(@NonNull Context context, + @NonNull LottieAnimationView lottieAnimationView) { + if (!SettingsThemeHelper.isExpressiveTheme(context)) { + return; + } + + for (String key : MATERIAL_COLOR_MAP.keySet()) { + final int color = context.getColor(MATERIAL_COLOR_MAP.get(key)); + lottieAnimationView.addValueCallback( + new KeyPath("**", key, "**"), + LottieProperty.COLOR_FILTER, + frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); + } + } } diff --git a/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java b/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java index 49f045f4423c..5df617c37945 100644 --- a/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java +++ b/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java @@ -41,7 +41,7 @@ import androidx.preference.PreferenceViewHolder; * xxxxxxx:allowDividerBelow="true" * */ -public class LayoutPreference extends Preference { +public class LayoutPreference extends Preference implements GroupSectionDividerMixin { private final View.OnClickListener mClickListener = v -> performClick(v); private boolean mAllowDividerAbove; diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt index d3a731688c24..3dd6c47833fd 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt @@ -201,3 +201,6 @@ interface RangeValue : ValueDescriptor { override fun isValidValue(context: Context, index: Int) = index in getMinValue(context)..getMaxValue(context) } + +/** A persistent preference that has a float value. */ +interface FloatPersistentPreference : PersistentPreference<Float> diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java index 03a2101544be..218983a55e1b 100644 --- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java +++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java @@ -31,7 +31,6 @@ import androidx.preference.CheckBoxPreference; import androidx.preference.PreferenceViewHolder; import com.android.settingslib.widget.preference.selector.R; -import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags; /** * Selector preference (checkbox or radio button) with an optional additional widget. @@ -180,10 +179,8 @@ public class SelectorWithWidgetPreference extends CheckBoxPreference { : getContext().getString(R.string.settings_label)); } - if (Flags.allowSetTitleMaxLines()) { - TextView title = (TextView) holder.findViewById(android.R.id.title); - title.setMaxLines(mTitleMaxLines); - } + TextView title = (TextView) holder.findViewById(android.R.id.title); + title.setMaxLines(mTitleMaxLines); } /** @@ -244,16 +241,12 @@ public class SelectorWithWidgetPreference extends CheckBoxPreference { setLayoutResource(R.layout.preference_selector_with_widget); setIconSpaceReserved(false); - if (Flags.allowSetTitleMaxLines()) { - final TypedArray a = - context.obtainStyledAttributes( - attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr, - defStyleRes); - mTitleMaxLines = - a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines, - DEFAULT_MAX_LINES); - a.recycle(); - } + final TypedArray a = + context.obtainStyledAttributes( + attrs, R.styleable.SelectorWithWidgetPreference, defStyleAttr, defStyleRes); + mTitleMaxLines = + a.getInt(R.styleable.SelectorWithWidgetPreference_titleMaxLines, DEFAULT_MAX_LINES); + a.recycle(); } @VisibleForTesting(otherwise = VisibleForTesting.NONE) diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index 1a043d5015b2..cc996c5a2120 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -97,6 +97,7 @@ flag { name: "settings_catalyst" namespace: "android_settings" description: "Settings catalyst project migration" + is_exported: true bug: "323791114" is_exported: true } @@ -106,6 +107,7 @@ flag { is_fixed_read_only: true namespace: "android_settings" description: "Enable WRITE_SYSTEM_PREFERENCE permission and appop" + is_exported: true bug: "375193223" is_exported: true } @@ -197,3 +199,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "disable_audio_sharing_auto_pick_fallback_in_ui" + namespace: "cross_device_experiences" + description: "Do not auto pick audio sharing fallback device in UI" + bug: "383469911" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index e1929b725a58..6cf9e83ef342 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -229,6 +229,8 @@ <string name="bluetooth_hearing_aid_right_active">Active (right only)</string> <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] --> <string name="bluetooth_hearing_aid_left_and_right_active">Active (left and right)</string> + <!-- Connected device settings.: Message when changing remote ambient state failed. [CHAR LIMIT=NONE] --> + <string name="bluetooth_hearing_device_ambient_error">Couldn\u2019t update surroundings</string> <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level. [CHAR LIMIT=NONE] --> <string name="bluetooth_active_media_only_battery_level">Active (media only). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUi.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUi.java new file mode 100644 index 000000000000..881a97bfadcd --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUi.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT; + +import android.bluetooth.BluetoothDevice; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; +import java.util.Map; + +/** Interface for the ambient volume UI. */ +public interface AmbientVolumeUi { + + /** Interface definition for a callback to be invoked when event happens in AmbientVolumeUi. */ + interface AmbientVolumeUiListener { + /** Called when the expand icon is clicked. */ + void onExpandIconClick(); + + /** Called when the ambient volume icon is clicked. */ + void onAmbientVolumeIconClick(); + + /** Called when the slider of the specified side is changed. */ + void onSliderValueChange(int side, int value); + }; + + /** The rotation degree of the expand icon when the UI is in collapsed mode. */ + float ROTATION_COLLAPSED = 0f; + /** The rotation degree of the expand icon when the UI is in expanded mode. */ + float ROTATION_EXPANDED = 180f; + + /** + * The default ambient volume level for hearing device ambient volume icon + * + * <p> This icon visually represents the current ambient volume. It displays separate + * levels for the left and right sides, each with 5 levels ranging from 0 to 4. + * + * <p> To represent the combined left/right levels with a single value, the following + * calculation is used: + * finalLevel = (leftLevel * 5) + rightLevel + * For example: + * <ul> + * <li>If left level is 2 and right level is 3, the final level will be 13 (2 * 5 + 3)</li> + * <li>If both left and right levels are 0, the final level will be 0</li> + * <li>If both left and right levels are 4, the final level will be 24</li> + * </ul> + */ + int AMBIENT_VOLUME_LEVEL_DEFAULT = 24; + /** + * The minimum ambient volume level for hearing device ambient volume icon + * + * @see #AMBIENT_VOLUME_LEVEL_DEFAULT + */ + int AMBIENT_VOLUME_LEVEL_MIN = 0; + /** + * The maximum ambient volume level for hearing device ambient volume icon + * + * @see #AMBIENT_VOLUME_LEVEL_DEFAULT + */ + int AMBIENT_VOLUME_LEVEL_MAX = 24; + + /** + * Ths side identifier for slider in collapsed mode which can unified control the ambient + * volume of all devices in the same set. + */ + int SIDE_UNIFIED = 999; + + /** All valid side of the sliders in the UI. */ + List<Integer> VALID_SIDES = List.of(SIDE_UNIFIED, SIDE_LEFT, SIDE_RIGHT); + + /** Sets if the UI is visible. */ + void setVisible(boolean visible); + + /** + * Sets if the UI is expandable between expanded and collapsed mode. + * + * <p> If the UI is not expandable, it implies the UI will always stay in collapsed mode + */ + void setExpandable(boolean expandable); + + /** @return if the UI is expandable. */ + boolean isExpandable(); + + /** Sets if the UI is in expanded mode. */ + void setExpanded(boolean expanded); + + /** @return if the UI is in expanded mode. */ + boolean isExpanded(); + + /** + * Sets if the UI is capable to mute the ambient of the remote device. + * + * <p> If the value is {@code false}, it implies the remote device ambient will always be + * unmute and can not be mute from the UI + */ + void setMutable(boolean mutable); + + /** @return if the UI is capable to mute the ambient of remote device. */ + boolean isMutable(); + + /** Sets if the UI shows mute state. */ + void setMuted(boolean muted); + + /** @return if the UI shows mute state */ + boolean isMuted(); + + /** + * Sets listener on the UI. + * + * @see AmbientVolumeUiListener + */ + void setListener(@Nullable AmbientVolumeUiListener listener); + + /** + * Sets up sliders in the UI. + * + * <p> For each side of device, the UI should hava a corresponding slider to control it's + * ambient volume. + * <p> For all devices in the same set, the UI should have a slider to control all devices' + * ambient volume at once. + * @param sideToDeviceMap the side and device mapping of all devices in the same set + */ + void setupSliders(@NonNull Map<Integer, BluetoothDevice> sideToDeviceMap); + + /** + * Sets if the slider is enabled. + * + * @param side the side of the slider + * @param enabled the enabled state + */ + void setSliderEnabled(int side, boolean enabled); + + /** + * Sets the slider value. + * + * @param side the side of the slider + * @param value the ambient value + */ + void setSliderValue(int side, int value); + + /** + * Sets the slider's minimum and maximum value. + * + * @param side the side of the slider + * @param min the minimum ambient value + * @param max the maximum ambient value + */ + void setSliderRange(int side, int min, int max); + + /** Updates the UI according to current state. */ + void updateLayout(); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUiController.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUiController.java new file mode 100644 index 000000000000..ce392b12516f --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeUiController.java @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED; +import static android.bluetooth.AudioInputControl.MUTE_MUTED; +import static android.bluetooth.BluetoothDevice.BOND_BONDED; + +import static com.android.settingslib.bluetooth.AmbientVolumeUi.SIDE_UNIFIED; +import static com.android.settingslib.bluetooth.AmbientVolumeUi.VALID_SIDES; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_INVALID; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT; +import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.util.ArraySet; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.settingslib.R; +import com.android.settingslib.utils.ThreadUtils; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +import java.util.Map; +import java.util.Set; + +/** This class controls ambient volume UI with local and remote ambient data. */ +public class AmbientVolumeUiController implements + HearingDeviceLocalDataManager.OnDeviceLocalDataChangeListener, + AmbientVolumeController.AmbientVolumeControlCallback, + AmbientVolumeUi.AmbientVolumeUiListener, BluetoothCallback, CachedBluetoothDevice.Callback { + + private static final boolean DEBUG = true; + private static final String TAG = "AmbientVolumeUiController"; + + private final Context mContext; + private final LocalBluetoothProfileManager mProfileManager; + private final BluetoothEventManager mEventManager; + private final AmbientVolumeUi mAmbientLayout; + private final AmbientVolumeController mVolumeController; + private final HearingDeviceLocalDataManager mLocalDataManager; + + private final Set<CachedBluetoothDevice> mCachedDevices = new ArraySet<>(); + private final BiMap<Integer, BluetoothDevice> mSideToDeviceMap = HashBiMap.create(); + private CachedBluetoothDevice mCachedDevice; + private boolean mShowUiWhenLocalDataExist = true; + + public AmbientVolumeUiController(@NonNull Context context, + @NonNull LocalBluetoothManager bluetoothManager, + @NonNull AmbientVolumeUi ambientLayout) { + mContext = context; + mProfileManager = bluetoothManager.getProfileManager(); + mEventManager = bluetoothManager.getEventManager(); + mAmbientLayout = ambientLayout; + mAmbientLayout.setListener(this); + mVolumeController = new AmbientVolumeController(mProfileManager, this); + mLocalDataManager = new HearingDeviceLocalDataManager(context); + mLocalDataManager.setOnDeviceLocalDataChangeListener(this, + ThreadUtils.getBackgroundExecutor()); + } + + @VisibleForTesting + public AmbientVolumeUiController(@NonNull Context context, + @NonNull LocalBluetoothManager bluetoothManager, + @NonNull AmbientVolumeUi ambientLayout, + @NonNull AmbientVolumeController volumeController, + @NonNull HearingDeviceLocalDataManager localDataManager) { + mContext = context; + mProfileManager = bluetoothManager.getProfileManager(); + mEventManager = bluetoothManager.getEventManager(); + mAmbientLayout = ambientLayout; + mVolumeController = volumeController; + mLocalDataManager = localDataManager; + } + + + @Override + public void onDeviceLocalDataChange(@NonNull String address, + @Nullable HearingDeviceLocalDataManager.Data data) { + if (data == null) { + // The local data is removed because the device is unpaired, do nothing + return; + } + if (DEBUG) { + Log.d(TAG, "onDeviceLocalDataChange, address:" + address + ", data:" + data); + } + for (BluetoothDevice device : mSideToDeviceMap.values()) { + if (device.getAnonymizedAddress().equals(address)) { + postOnMainThread(() -> loadLocalDataToUi(device)); + return; + } + } + } + + @Override + public void onVolumeControlServiceConnected() { + mCachedDevices.forEach(device -> mVolumeController.registerCallback( + ThreadUtils.getBackgroundExecutor(), device.getDevice())); + } + + @Override + public void onAmbientChanged(@NonNull BluetoothDevice device, int gainSettings) { + if (DEBUG) { + Log.d(TAG, "onAmbientChanged, value:" + gainSettings + ", device:" + device); + } + HearingDeviceLocalDataManager.Data data = mLocalDataManager.get(device); + final boolean expanded = mAmbientLayout.isExpanded(); + final boolean isInitiatedFromUi = (expanded && data.ambient() == gainSettings) + || (!expanded && data.groupAmbient() == gainSettings); + if (isInitiatedFromUi) { + // The change is initiated from UI, no need to update UI + return; + } + + // We have to check if we need to expand the controls by getting all remote + // device's ambient value, delay for a while to wait all remote devices update + // to the latest value to avoid unnecessary expand action. + postDelayedOnMainThread(this::refresh, 1200L); + } + + @Override + public void onMuteChanged(@NonNull BluetoothDevice device, int mute) { + if (DEBUG) { + Log.d(TAG, "onMuteChanged, mute:" + mute + ", device:" + device); + } + final boolean muted = mAmbientLayout.isMuted(); + boolean isInitiatedFromUi = (muted && mute == MUTE_MUTED) + || (!muted && mute == MUTE_NOT_MUTED); + if (isInitiatedFromUi) { + // The change is initiated from UI, no need to update UI + return; + } + + // We have to check if we need to mute the devices by getting all remote + // device's mute state, delay for a while to wait all remote devices update + // to the latest value. + postDelayedOnMainThread(this::refresh, 1200L); + } + + @Override + public void onCommandFailed(@NonNull BluetoothDevice device) { + Log.w(TAG, "onCommandFailed, device:" + device); + postOnMainThread(() -> { + showErrorToast(R.string.bluetooth_hearing_device_ambient_error); + refresh(); + }); + } + + @Override + public void onExpandIconClick() { + mSideToDeviceMap.forEach((s, d) -> { + if (!mAmbientLayout.isMuted()) { + // Apply previous collapsed/expanded volume to remote device + HearingDeviceLocalDataManager.Data data = mLocalDataManager.get(d); + int volume = mAmbientLayout.isExpanded() + ? data.ambient() : data.groupAmbient(); + mVolumeController.setAmbient(d, volume); + } + // Update new value to local data + mLocalDataManager.updateAmbientControlExpanded(d, + mAmbientLayout.isExpanded()); + }); + mLocalDataManager.flush(); + } + + @Override + public void onAmbientVolumeIconClick() { + if (!mAmbientLayout.isMuted()) { + loadLocalDataToUi(); + } + for (BluetoothDevice device : mSideToDeviceMap.values()) { + mVolumeController.setMuted(device, mAmbientLayout.isMuted()); + } + } + + @Override + public void onSliderValueChange(int side, int value) { + if (DEBUG) { + Log.d(TAG, "onSliderValueChange: side=" + side + ", value=" + value); + } + setVolumeIfValid(side, value); + + Runnable setAmbientRunnable = () -> { + if (side == SIDE_UNIFIED) { + mSideToDeviceMap.forEach((s, d) -> mVolumeController.setAmbient(d, value)); + } else { + final BluetoothDevice device = mSideToDeviceMap.get(side); + mVolumeController.setAmbient(device, value); + } + }; + + if (mAmbientLayout.isMuted()) { + // User drag on the volume slider when muted. Unmute the devices first. + mAmbientLayout.setMuted(false); + + for (BluetoothDevice device : mSideToDeviceMap.values()) { + mVolumeController.setMuted(device, false); + } + // Restore the value before muted + loadLocalDataToUi(); + // Delay set ambient on remote device since the immediately sequential command + // might get failed sometimes + postDelayedOnMainThread(setAmbientRunnable, 1000L); + } else { + setAmbientRunnable.run(); + } + } + + @Override + public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice, + int state, int bluetoothProfile) { + if (bluetoothProfile == BluetoothProfile.VOLUME_CONTROL + && state == BluetoothProfile.STATE_CONNECTED + && mCachedDevices.contains(cachedDevice)) { + // After VCP connected, AICS may not ready yet and still return invalid value, delay + // a while to wait AICS ready as a workaround + postDelayedOnMainThread(this::refresh, 1000L); + } + } + + @Override + public void onDeviceAttributesChanged() { + mCachedDevices.forEach(device -> { + device.unregisterCallback(this); + mVolumeController.unregisterCallback(device.getDevice()); + }); + postOnMainThread(()-> { + loadDevice(mCachedDevice); + ThreadUtils.postOnBackgroundThread(()-> { + mCachedDevices.forEach(device -> { + device.registerCallback(ThreadUtils.getBackgroundExecutor(), this); + mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(), + device.getDevice()); + }); + }); + }); + } + + /** + * Registers callbacks and listeners, this should be called when needs to start listening to + * events. + */ + public void start() { + mEventManager.registerCallback(this); + mLocalDataManager.start(); + mCachedDevices.forEach(device -> { + device.registerCallback(ThreadUtils.getBackgroundExecutor(), this); + mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(), + device.getDevice()); + }); + } + + /** + * Unregisters callbacks and listeners, this should be called when no longer needs to listen to + * events. + */ + public void stop() { + mEventManager.unregisterCallback(this); + mLocalDataManager.stop(); + mCachedDevices.forEach(device -> { + device.unregisterCallback(this); + mVolumeController.unregisterCallback(device.getDevice()); + }); + } + + /** + * Loads all devices in the same set with {@code cachedDevice} and create corresponding sliders. + * + * <p>If the devices has valid ambient control points, the ambient volume UI will be visible. + * @param cachedDevice the remote device + */ + public void loadDevice(CachedBluetoothDevice cachedDevice) { + if (DEBUG) { + Log.d(TAG, "loadDevice, device=" + cachedDevice); + } + mCachedDevice = cachedDevice; + mSideToDeviceMap.clear(); + mCachedDevices.clear(); + boolean deviceSupportVcp = + cachedDevice != null && cachedDevice.getProfiles().stream().anyMatch( + p -> p instanceof VolumeControlProfile); + if (!deviceSupportVcp) { + mAmbientLayout.setVisible(false); + return; + } + + // load devices in the same set + if (VALID_SIDES.contains(cachedDevice.getDeviceSide()) + && cachedDevice.getBondState() == BOND_BONDED) { + mSideToDeviceMap.put(cachedDevice.getDeviceSide(), cachedDevice.getDevice()); + mCachedDevices.add(cachedDevice); + } + for (CachedBluetoothDevice memberDevice : cachedDevice.getMemberDevice()) { + if (VALID_SIDES.contains(memberDevice.getDeviceSide()) + && memberDevice.getBondState() == BOND_BONDED) { + mSideToDeviceMap.put(memberDevice.getDeviceSide(), memberDevice.getDevice()); + mCachedDevices.add(memberDevice); + } + } + + mAmbientLayout.setExpandable(mSideToDeviceMap.size() > 1); + mAmbientLayout.setupSliders(mSideToDeviceMap); + refresh(); + } + + /** Refreshes the ambient volume UI. */ + public void refresh() { + if (isAmbientControlAvailable()) { + mAmbientLayout.setVisible(true); + loadRemoteDataToUi(); + } else { + mAmbientLayout.setVisible(false); + } + } + + /** Sets if the ambient volume UI should be visible when local ambient data exist. */ + public void setShowUiWhenLocalDataExist(boolean shouldShow) { + mShowUiWhenLocalDataExist = shouldShow; + } + + /** Updates the ambient sliders according to current state. */ + private void updateSliderUi() { + boolean isAnySliderEnabled = false; + for (Map.Entry<Integer, BluetoothDevice> entry : mSideToDeviceMap.entrySet()) { + final int side = entry.getKey(); + final BluetoothDevice device = entry.getValue(); + final boolean enabled = isDeviceConnectedToVcp(device) + && mVolumeController.isAmbientControlAvailable(device); + isAnySliderEnabled |= enabled; + mAmbientLayout.setSliderEnabled(side, enabled); + } + mAmbientLayout.setSliderEnabled(SIDE_UNIFIED, isAnySliderEnabled); + mAmbientLayout.updateLayout(); + } + + /** Sets the ambient to the corresponding control slider. */ + private void setVolumeIfValid(int side, int volume) { + if (volume == INVALID_VOLUME) { + return; + } + mAmbientLayout.setSliderValue(side, volume); + // Update new value to local data + if (side == SIDE_UNIFIED) { + mSideToDeviceMap.forEach((s, d) -> mLocalDataManager.updateGroupAmbient(d, volume)); + } else { + mLocalDataManager.updateAmbient(mSideToDeviceMap.get(side), volume); + } + mLocalDataManager.flush(); + } + + private void loadLocalDataToUi() { + mSideToDeviceMap.forEach((s, d) -> loadLocalDataToUi(d)); + } + + private void loadLocalDataToUi(BluetoothDevice device) { + final HearingDeviceLocalDataManager.Data data = mLocalDataManager.get(device); + if (DEBUG) { + Log.d(TAG, "loadLocalDataToUi, data=" + data + ", device=" + device); + } + if (isDeviceConnectedToVcp(device) && !mAmbientLayout.isMuted()) { + final int side = mSideToDeviceMap.inverse().getOrDefault(device, SIDE_INVALID); + setVolumeIfValid(side, data.ambient()); + setVolumeIfValid(SIDE_UNIFIED, data.groupAmbient()); + } + setAmbientControlExpanded(data.ambientControlExpanded()); + updateSliderUi(); + } + + private void loadRemoteDataToUi() { + BluetoothDevice leftDevice = mSideToDeviceMap.get(SIDE_LEFT); + AmbientVolumeController.RemoteAmbientState leftState = + mVolumeController.refreshAmbientState(leftDevice); + BluetoothDevice rightDevice = mSideToDeviceMap.get(SIDE_RIGHT); + AmbientVolumeController.RemoteAmbientState rightState = + mVolumeController.refreshAmbientState(rightDevice); + if (DEBUG) { + Log.d(TAG, "loadRemoteDataToUi, left=" + leftState + ", right=" + rightState); + } + mSideToDeviceMap.forEach((side, device) -> { + int ambientMax = mVolumeController.getAmbientMax(device); + int ambientMin = mVolumeController.getAmbientMin(device); + if (ambientMin != ambientMax) { + mAmbientLayout.setSliderRange(side, ambientMin, ambientMax); + mAmbientLayout.setSliderRange(SIDE_UNIFIED, ambientMin, ambientMax); + } + }); + + // Update ambient volume + final int leftAmbient = leftState != null ? leftState.gainSetting() : INVALID_VOLUME; + final int rightAmbient = rightState != null ? rightState.gainSetting() : INVALID_VOLUME; + if (mAmbientLayout.isExpanded()) { + setVolumeIfValid(SIDE_LEFT, leftAmbient); + setVolumeIfValid(SIDE_RIGHT, rightAmbient); + } else { + if (leftAmbient != rightAmbient && leftAmbient != INVALID_VOLUME + && rightAmbient != INVALID_VOLUME) { + setVolumeIfValid(SIDE_LEFT, leftAmbient); + setVolumeIfValid(SIDE_RIGHT, rightAmbient); + setAmbientControlExpanded(true); + } else { + int unifiedAmbient = leftAmbient != INVALID_VOLUME ? leftAmbient : rightAmbient; + setVolumeIfValid(SIDE_UNIFIED, unifiedAmbient); + } + } + // Initialize local data between side and group value + initLocalAmbientDataIfNeeded(); + + // Update mute state + boolean mutable = true; + boolean muted = true; + if (isDeviceConnectedToVcp(leftDevice) && leftState != null) { + mutable &= leftState.isMutable(); + muted &= leftState.isMuted(); + } + if (isDeviceConnectedToVcp(rightDevice) && rightState != null) { + mutable &= rightState.isMutable(); + muted &= rightState.isMuted(); + } + mAmbientLayout.setMutable(mutable); + mAmbientLayout.setMuted(muted); + + // Ensure remote device mute state is synced + syncMuteStateIfNeeded(leftDevice, leftState, muted); + syncMuteStateIfNeeded(rightDevice, rightState, muted); + + updateSliderUi(); + } + + private void setAmbientControlExpanded(boolean expanded) { + mAmbientLayout.setExpanded(expanded); + mSideToDeviceMap.forEach((s, d) -> { + // Update new value to local data + mLocalDataManager.updateAmbientControlExpanded(d, expanded); + }); + mLocalDataManager.flush(); + } + + /** Checks if any device in the same set has valid ambient control points */ + private boolean isAmbientControlAvailable() { + for (BluetoothDevice device : mSideToDeviceMap.values()) { + if (mShowUiWhenLocalDataExist) { + // Found local ambient data + if (mLocalDataManager.get(device).hasAmbientData()) { + return true; + } + } + // Found remote ambient control points + if (mVolumeController.isAmbientControlAvailable(device)) { + return true; + } + } + return false; + } + + private void initLocalAmbientDataIfNeeded() { + int smallerVolumeAmongGroup = Integer.MAX_VALUE; + for (BluetoothDevice device : mSideToDeviceMap.values()) { + HearingDeviceLocalDataManager.Data data = mLocalDataManager.get(device); + if (data.ambient() != INVALID_VOLUME) { + smallerVolumeAmongGroup = Math.min(data.ambient(), smallerVolumeAmongGroup); + } else if (data.groupAmbient() != INVALID_VOLUME) { + // Initialize side ambient from group ambient value + mLocalDataManager.updateAmbient(device, data.groupAmbient()); + } + } + if (smallerVolumeAmongGroup != Integer.MAX_VALUE) { + for (BluetoothDevice device : mSideToDeviceMap.values()) { + HearingDeviceLocalDataManager.Data data = mLocalDataManager.get(device); + if (data.groupAmbient() == INVALID_VOLUME) { + // Initialize group ambient from smaller side ambient value + mLocalDataManager.updateGroupAmbient(device, smallerVolumeAmongGroup); + } + } + } + mLocalDataManager.flush(); + } + + private void syncMuteStateIfNeeded(@Nullable BluetoothDevice device, + @Nullable AmbientVolumeController.RemoteAmbientState state, boolean muted) { + if (isDeviceConnectedToVcp(device) && state != null && state.isMutable()) { + if (state.isMuted() != muted) { + mVolumeController.setMuted(device, muted); + } + } + } + + private boolean isDeviceConnectedToVcp(@Nullable BluetoothDevice device) { + return device != null && device.isConnected() + && mProfileManager.getVolumeControlProfile().getConnectionStatus(device) + == BluetoothProfile.STATE_CONNECTED; + } + + private void postOnMainThread(Runnable runnable) { + mContext.getMainThreadHandler().post(runnable); + } + + private void postDelayedOnMainThread(Runnable runnable, long delay) { + mContext.getMainThreadHandler().postDelayed(runnable, delay); + } + + private void showErrorToast(int stringResId) { + Toast.makeText(mContext, stringResId, Toast.LENGTH_SHORT).show(); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 429e4c958f05..0c642d7b8f98 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -656,7 +656,8 @@ public class BluetoothUtils { @WorkerThread public static boolean isAudioSharingHysteresisModeFixAvailable(@Nullable Context context) { return (audioSharingHysteresisModeFix() && Flags.enableLeAudioSharing()) - || (context != null && isAudioSharingPreviewEnabled(context.getContentResolver())); + || (context != null && Flags.audioSharingDeveloperOption() + && getAudioSharingPreviewValue(context.getContentResolver())); } /** Returns if the le audio sharing is enabled. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java index 6725558cd2bd..3cd37320243f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java @@ -148,6 +148,14 @@ public class HearingDeviceLocalDataManager { } } + /** Flushes the data into Settings . */ + public synchronized void flush() { + if (!mIsStarted) { + return; + } + putAmbientVolumeSettings(); + } + /** * Puts the local data of the corresponding hearing device. * @@ -274,9 +282,6 @@ public class HearingDeviceLocalDataManager { notifyIfDataChanged(mAddrToDataMap, updatedAddrToDataMap); mAddrToDataMap.clear(); mAddrToDataMap.putAll(updatedAddrToDataMap); - if (DEBUG) { - Log.v(TAG, "getLocalDataFromSettings, " + mAddrToDataMap + ", manager: " + this); - } } } @@ -287,12 +292,10 @@ public class HearingDeviceLocalDataManager { builder.append(KEY_ADDR).append("=").append(entry.getKey()); builder.append(entry.getValue().toSettingsFormat()).append(";"); } - if (DEBUG) { - Log.v(TAG, "putAmbientVolumeSettings, " + builder + ", manager: " + this); - } - Settings.Global.putStringForUser(mContext.getContentResolver(), - LOCAL_AMBIENT_VOLUME_SETTINGS, builder.toString(), - UserHandle.USER_SYSTEM); + ThreadUtils.postOnBackgroundThread(() -> { + Settings.Global.putStringForUser(mContext.getContentResolver(), + LOCAL_AMBIENT_VOLUME_SETTINGS, builder.toString(), UserHandle.USER_SYSTEM); + }); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index b52ed42d567f..2c99a2d4818c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -101,6 +101,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { public @interface BroadcastState {} private static final String SETTINGS_PKG = "com.android.settings"; + private static final String SYSUI_PKG = "com.android.systemui"; private static final String TAG = "LocalBluetoothLeBroadcast"; private static final boolean DEBUG = BluetoothUtils.D; @@ -216,6 +217,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } setLatestBroadcastId(broadcastId); setAppSourceName(mNewAppSourceName, /* updateContentResolver= */ true); + notifyBroadcastStateChange(BROADCAST_STATE_ON); } @Override @@ -232,7 +234,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId); } setLatestBluetoothLeBroadcastMetadata(metadata); - notifyBroadcastStateChange(BROADCAST_STATE_ON); } @Override @@ -1247,8 +1248,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } private void notifyBroadcastStateChange(@BroadcastState int state) { - if (!mContext.getPackageName().equals(SETTINGS_PKG)) { - Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings."); + String packageName = mContext.getPackageName(); + if (!packageName.equals(SETTINGS_PKG) && !packageName.equals(SYSUI_PKG)) { + Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings or SystemUI."); return; } if (isWorkProfile(mContext)) { @@ -1257,8 +1259,8 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { } Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE); intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state); - intent.setPackage(mContext.getPackageName()); - Log.d(TAG, "notifyBroadcastStateChange for state = " + state); + intent.setPackage(SETTINGS_PKG); + Log.d(TAG, "notifyBroadcastStateChange for state = " + state + " by pkg = " + packageName); mContext.sendBroadcast(intent); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index cf452314163f..c9aac91f1320 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -21,6 +21,7 @@ import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_ import android.annotation.IntDef; import android.annotation.MainThread; +import android.app.ActivityManager; import android.app.AppGlobals; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -1643,7 +1644,7 @@ public class AccessPoint implements Comparable<AccessPoint> { CharSequence appLabel = ""; ApplicationInfo appInfo = null; try { - int userId = UserHandle.getUserId(UserHandle.USER_CURRENT); + int userId = ActivityManager.getCurrentUser(); appInfo = packageManager.getApplicationInfoAsUser(packageName, 0 /* flags */, userId); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Failed to get app info", e); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt index e01f27964733..c71b19c9235f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt @@ -501,7 +501,7 @@ open class WifiUtils { val wifiManager = context.getSystemService(WifiManager::class.java) ?: return@launch val aapmManager = context.getSystemService(AdvancedProtectionManager::class.java) if (isAdvancedProtectionEnabled(aapmManager)) { - val intent = aapmManager.createSupportIntent( + val intent = AdvancedProtectionManager.createSupportIntent( AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP, AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION) onStartActivity(intent) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeUiControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeUiControllerTest.java new file mode 100644 index 000000000000..8b606e299971 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeUiControllerTest.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static android.bluetooth.AudioInputControl.MUTE_DISABLED; +import static android.bluetooth.AudioInputControl.MUTE_MUTED; +import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED; +import static android.bluetooth.BluetoothDevice.BOND_BONDED; + +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.robolectric.Shadows.shadowOf; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.robolectric.RobolectricTestRunner; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executor; + +/** Tests for {@link AmbientVolumeUiController}. */ +@RunWith(RobolectricTestRunner.class) +public class AmbientVolumeUiControllerTest { + + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + private static final String TEST_ADDRESS = "00:00:00:00:11"; + private static final String TEST_MEMBER_ADDRESS = "00:00:00:00:22"; + + @Mock + LocalBluetoothManager mBluetoothManager; + @Mock + LocalBluetoothProfileManager mProfileManager; + @Mock + BluetoothEventManager mEventManager; + @Mock + VolumeControlProfile mVolumeControlProfile; + @Mock + AmbientVolumeUi mAmbientLayout; + @Mock + private AmbientVolumeController mVolumeController; + @Mock + private HearingDeviceLocalDataManager mLocalDataManager; + @Mock + private CachedBluetoothDevice mCachedDevice; + @Mock + private CachedBluetoothDevice mCachedMemberDevice; + @Mock + private BluetoothDevice mDevice; + @Mock + private BluetoothDevice mMemberDevice; + @Mock + private Handler mTestHandler; + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + private AmbientVolumeUiController mController; + + @Before + public void setUp() { + when(mBluetoothManager.getProfileManager()).thenReturn(mProfileManager); + when(mBluetoothManager.getEventManager()).thenReturn(mEventManager); + + mController = spy(new AmbientVolumeUiController(mContext, mBluetoothManager, + mAmbientLayout, mVolumeController, mLocalDataManager)); + + when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile); + when(mVolumeControlProfile.getConnectionStatus(mDevice)).thenReturn( + BluetoothProfile.STATE_CONNECTED); + when(mVolumeControlProfile.getConnectionStatus(mMemberDevice)).thenReturn( + BluetoothProfile.STATE_CONNECTED); + when(mVolumeController.isAmbientControlAvailable(mDevice)).thenReturn(true); + when(mVolumeController.isAmbientControlAvailable(mMemberDevice)).thenReturn(true); + when(mLocalDataManager.get(any(BluetoothDevice.class))).thenReturn( + new HearingDeviceLocalDataManager.Data.Builder().build()); + + when(mContext.getMainThreadHandler()).thenReturn(mTestHandler); + Answer<Object> answer = invocationOnMock -> { + invocationOnMock.getArgument(0, Runnable.class).run(); + return null; + }; + when(mTestHandler.post(any(Runnable.class))).thenAnswer(answer); + when(mTestHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(answer); + + prepareDevice(/* hasMember= */ true); + mController.loadDevice(mCachedDevice); + Mockito.reset(mController); + Mockito.reset(mAmbientLayout); + } + + @Test + public void loadDevice_deviceWithoutMember_controlNotExpandable() { + prepareDevice(/* hasMember= */ false); + + mController.loadDevice(mCachedDevice); + + verify(mAmbientLayout).setExpandable(false); + } + + @Test + public void loadDevice_deviceWithMember_controlExpandable() { + prepareDevice(/* hasMember= */ true); + + mController.loadDevice(mCachedDevice); + + verify(mAmbientLayout).setExpandable(true); + } + + @Test + public void loadDevice_deviceNotSupportVcp_ambientLayoutGone() { + when(mCachedDevice.getProfiles()).thenReturn(List.of()); + + mController.loadDevice(mCachedDevice); + + verify(mAmbientLayout).setVisible(false); + } + + @Test + public void loadDevice_ambientControlNotAvailable_ambientLayoutGone() { + when(mVolumeController.isAmbientControlAvailable(mDevice)).thenReturn(false); + when(mVolumeController.isAmbientControlAvailable(mMemberDevice)).thenReturn(false); + + mController.loadDevice(mCachedDevice); + + verify(mAmbientLayout).setVisible(false); + } + + @Test + public void loadDevice_supportVcpAndAmbientControlAvailable_ambientLayoutVisible() { + when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile)); + when(mVolumeController.isAmbientControlAvailable(mDevice)).thenReturn(true); + + mController.loadDevice(mCachedDevice); + + verify(mAmbientLayout).setVisible(true); + } + + @Test + public void start_callbackRegistered() { + mController.start(); + + verify(mEventManager).registerCallback(mController); + verify(mLocalDataManager).start(); + verify(mVolumeController).registerCallback(any(Executor.class), eq(mDevice)); + verify(mVolumeController).registerCallback(any(Executor.class), eq(mMemberDevice)); + verify(mCachedDevice).registerCallback(any(Executor.class), + any(CachedBluetoothDevice.Callback.class)); + verify(mCachedMemberDevice).registerCallback(any(Executor.class), + any(CachedBluetoothDevice.Callback.class)); + } + + @Test + public void stop_callbackUnregistered() { + mController.stop(); + + verify(mEventManager).unregisterCallback(mController); + verify(mLocalDataManager).stop(); + verify(mVolumeController).unregisterCallback(mDevice); + verify(mVolumeController).unregisterCallback(mMemberDevice); + verify(mCachedDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class)); + verify(mCachedMemberDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class)); + } + + @Test + public void onDeviceLocalDataChange_verifySetExpandedAndDataUpdated() { + final boolean testExpanded = true; + HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder() + .ambient(0).groupAmbient(0).ambientControlExpanded(testExpanded).build(); + when(mLocalDataManager.get(mDevice)).thenReturn(data); + + mController.onDeviceLocalDataChange(TEST_ADDRESS, data); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mAmbientLayout).setExpanded(testExpanded); + verifyDeviceDataUpdated(mDevice); + } + + @Test + public void onAmbientChanged_refreshWhenNotInitiateFromUi() { + HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder() + .ambient(10).groupAmbient(10).ambientControlExpanded(true).build(); + when(mLocalDataManager.get(mDevice)).thenReturn(data); + when(mAmbientLayout.isExpanded()).thenReturn(true); + + mController.onAmbientChanged(mDevice, 10); + verify(mController, never()).refresh(); + + mController.onAmbientChanged(mDevice, 20); + verify(mController).refresh(); + } + + @Test + public void onMuteChanged_refreshWhenNotInitiateFromUi() { + AmbientVolumeController.RemoteAmbientState state = + new AmbientVolumeController.RemoteAmbientState(MUTE_NOT_MUTED, 0); + when(mVolumeController.refreshAmbientState(mDevice)).thenReturn(state); + when(mAmbientLayout.isExpanded()).thenReturn(false); + + mController.onMuteChanged(mDevice, MUTE_NOT_MUTED); + verify(mController, never()).refresh(); + + mController.onMuteChanged(mDevice, MUTE_MUTED); + verify(mController).refresh(); + } + + @Test + public void refresh_leftAndRightDifferentGainSetting_expandControl() { + prepareRemoteData(mDevice, 10, MUTE_NOT_MUTED); + prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED); + when(mAmbientLayout.isExpanded()).thenReturn(false); + + mController.refresh(); + + verify(mAmbientLayout).setExpanded(true); + } + + @Test + public void refresh_oneSideNotMutable_controlNotMutableAndNotMuted() { + prepareRemoteData(mDevice, 10, MUTE_DISABLED); + prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED); + + mController.refresh(); + + verify(mAmbientLayout).setMutable(false); + verify(mAmbientLayout).setMuted(false); + } + + @Test + public void refresh_oneSideNotMuted_controlNotMutedAndSyncToRemote() { + prepareRemoteData(mDevice, 10, MUTE_MUTED); + prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED); + + mController.refresh(); + + verify(mAmbientLayout).setMutable(true); + verify(mAmbientLayout).setMuted(false); + verify(mVolumeController).setMuted(mDevice, false); + } + + private void prepareDevice(boolean hasMember) { + when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT); + when(mCachedDevice.getDevice()).thenReturn(mDevice); + when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED); + when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile)); + when(mDevice.getAddress()).thenReturn(TEST_ADDRESS); + when(mDevice.getAnonymizedAddress()).thenReturn(TEST_ADDRESS); + when(mDevice.isConnected()).thenReturn(true); + if (hasMember) { + when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedMemberDevice)); + when(mCachedMemberDevice.getDeviceSide()).thenReturn(SIDE_RIGHT); + when(mCachedMemberDevice.getDevice()).thenReturn(mMemberDevice); + when(mCachedMemberDevice.getBondState()).thenReturn(BOND_BONDED); + when(mCachedMemberDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile)); + when(mMemberDevice.getAddress()).thenReturn(TEST_MEMBER_ADDRESS); + when(mMemberDevice.getAnonymizedAddress()).thenReturn(TEST_MEMBER_ADDRESS); + when(mMemberDevice.isConnected()).thenReturn(true); + } else { + when(mCachedDevice.getMemberDevice()).thenReturn(Set.of()); + } + } + + private void prepareRemoteData(BluetoothDevice device, int gainSetting, int mute) { + when(mVolumeController.refreshAmbientState(device)).thenReturn( + new AmbientVolumeController.RemoteAmbientState(gainSetting, mute)); + } + + private void verifyDeviceDataUpdated(BluetoothDevice device) { + verify(mLocalDataManager).updateAmbient(eq(device), anyInt()); + verify(mLocalDataManager).updateGroupAmbient(eq(device), anyInt()); + verify(mLocalDataManager).updateAmbientControlExpanded(eq(device), + anyBoolean()); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index fa5d54283a17..ab9f871444b4 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -970,8 +970,10 @@ public class BluetoothUtilsTest { when(cachedBluetoothDevice2.getGroupId()).thenReturn(2); BluetoothDevice device1 = mock(BluetoothDevice.class); + when(mCachedBluetoothDevice.getDevice()).thenReturn(device1); when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice); BluetoothDevice device2 = mock(BluetoothDevice.class); + when(cachedBluetoothDevice2.getDevice()).thenReturn(device2); when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1, device2)); @@ -991,8 +993,10 @@ public class BluetoothUtilsTest { when(cachedBluetoothDevice2.getGroupId()).thenReturn(2); BluetoothDevice device1 = mock(BluetoothDevice.class); + when(mCachedBluetoothDevice.getDevice()).thenReturn(device1); when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice); BluetoothDevice device2 = mock(BluetoothDevice.class); + when(cachedBluetoothDevice2.getDevice()).thenReturn(device2); when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1, device2)); @@ -1012,8 +1016,10 @@ public class BluetoothUtilsTest { when(cachedBluetoothDevice2.getGroupId()).thenReturn(2); BluetoothDevice device1 = mock(BluetoothDevice.class); + when(mCachedBluetoothDevice.getDevice()).thenReturn(device1); when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice); BluetoothDevice device2 = mock(BluetoothDevice.class); + when(cachedBluetoothDevice2.getDevice()).thenReturn(device2); when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device2)); @@ -1035,10 +1041,13 @@ public class BluetoothUtilsTest { when(cachedBluetoothDevice3.getGroupId()).thenReturn(3); BluetoothDevice device1 = mock(BluetoothDevice.class); + when(mCachedBluetoothDevice.getDevice()).thenReturn(device1); when(mDeviceManager.findDevice(device1)).thenReturn(mCachedBluetoothDevice); BluetoothDevice device2 = mock(BluetoothDevice.class); + when(cachedBluetoothDevice2.getDevice()).thenReturn(device2); when(mDeviceManager.findDevice(device2)).thenReturn(cachedBluetoothDevice2); BluetoothDevice device3 = mock(BluetoothDevice.class); + when(cachedBluetoothDevice3.getDevice()).thenReturn(device3); when(mDeviceManager.findDevice(device3)).thenReturn(cachedBluetoothDevice3); when(mAssistant.getAllConnectedDevices()) @@ -1280,6 +1289,8 @@ public class BluetoothUtilsTest { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX); mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION); + Settings.Global.putInt(mContext.getContentResolver(), + BluetoothUtils.DEVELOPER_OPTION_PREVIEW_KEY, 1); assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isTrue(); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java index 6d83588e0f6e..6485636079dd 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java @@ -31,6 +31,8 @@ import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; +import com.android.settingslib.utils.ThreadUtils; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -49,7 +51,10 @@ import java.util.Map; /** Tests for {@link HearingDeviceLocalDataManager}. */ @RunWith(RobolectricTestRunner.class) -@Config(shadows = {HearingDeviceLocalDataManagerTest.ShadowGlobal.class}) +@Config(shadows = { + HearingDeviceLocalDataManagerTest.ShadowGlobal.class, + HearingDeviceLocalDataManagerTest.ShadowThreadUtils.class, +}) public class HearingDeviceLocalDataManagerTest { private static final String TEST_ADDRESS = "XX:XX:XX:XX:11:22"; @@ -249,4 +254,12 @@ public class HearingDeviceLocalDataManagerTest { return sDataMap.computeIfAbsent(cr, k -> new HashMap<>()); } } + + @Implements(value = ThreadUtils.class) + public static class ShadowThreadUtils { + @Implementation + protected static void postOnBackgroundThread(Runnable runnable) { + runnable.run(); + } + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java index 2b8b3b74dab9..c939c770b63d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java @@ -21,9 +21,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import android.app.Application; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -33,10 +30,8 @@ import androidx.preference.PreferenceViewHolder; import androidx.test.core.app.ApplicationProvider; import com.android.settingslib.widget.preference.selector.R; -import com.android.settingslib.widget.selectorwithwidgetpreference.flags.Flags; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; @@ -45,7 +40,6 @@ import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class SelectorWithWidgetPreferenceTest { - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Application mContext; private SelectorWithWidgetPreference mPreference; @@ -128,26 +122,6 @@ public class SelectorWithWidgetPreferenceTest { } @Test - @DisableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES) - public void onBindViewHolder_titleMaxLinesSet_flagOff_titleMaxLinesMatchesDefault() { - final int titleMaxLines = 5; - AttributeSet attributeSet = Robolectric.buildAttributeSet() - .addAttribute(R.attr.titleMaxLines, String.valueOf(titleMaxLines)) - .build(); - mPreference = new SelectorWithWidgetPreference(mContext, attributeSet); - View view = LayoutInflater.from(mContext) - .inflate(mPreference.getLayoutResource(), null /* root */); - PreferenceViewHolder preferenceViewHolder = - PreferenceViewHolder.createInstanceForTests(view); - - mPreference.onBindViewHolder(preferenceViewHolder); - - TextView title = (TextView) preferenceViewHolder.findViewById(android.R.id.title); - assertThat(title.getMaxLines()).isEqualTo(SelectorWithWidgetPreference.DEFAULT_MAX_LINES); - } - - @Test - @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES) public void onBindViewHolder_noTitleMaxLinesSet_titleMaxLinesMatchesDefault() { AttributeSet attributeSet = Robolectric.buildAttributeSet().build(); mPreference = new SelectorWithWidgetPreference(mContext, attributeSet); @@ -163,7 +137,6 @@ public class SelectorWithWidgetPreferenceTest { } @Test - @EnableFlags(Flags.FLAG_ALLOW_SET_TITLE_MAX_LINES) public void onBindViewHolder_titleMaxLinesSet_titleMaxLinesUpdated() { final int titleMaxLines = 5; AttributeSet attributeSet = Robolectric.buildAttributeSet() diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index 91ac34ac8233..de7c450d8d39 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -148,27 +148,7 @@ public final class DeviceConfigService extends Binder { // TODO(b/364399200): use filter to skip instead? return; } - - ArrayList<String> missingFiles = new ArrayList<String>(); - for (String fileName : sAconfigTextProtoFilesOnDevice) { - File aconfigFile = new File(fileName); - if (!aconfigFile.exists()) { - missingFiles.add(fileName); - } - } - - if (missingFiles.isEmpty()) { - pw.println("\nAconfig flags:"); - for (String name : MyShellCommand.listAllAconfigFlags(iprovider)) { - pw.println(name); - } - } else { - pw.println("\nFailed to dump aconfig flags due to missing files:"); - for (String fileName : missingFiles) { - pw.println(fileName); - } - } - } + } private static HashSet<String> getAconfigFlagNamesInDeviceConfig() { HashSet<String> nameSet = new HashSet<String>(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 1c4def39eaa0..e01cb84f60ae 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -16,6 +16,19 @@ package com.android.providers.settings; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_DEVICE_SPECIFIC_CONFIG; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_GLOBAL; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_LOCALE; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_LOCK_SETTINGS; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_NETWORK_POLICIES; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SECURE; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS_2; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SOFTAP_CONFIG; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SYSTEM; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_NEW_CONFIG; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_SETTINGS_BACKUP_DATA; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -99,22 +112,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final int NULL_SIZE = -1; private static final float FONT_SCALE_DEF_VALUE = 1.0f; - private static final String KEY_SYSTEM = "system"; - private static final String KEY_SECURE = "secure"; - private static final String KEY_GLOBAL = "global"; - private static final String KEY_LOCALE = "locale"; - private static final String KEY_LOCK_SETTINGS = "lock_settings"; - private static final String KEY_SOFTAP_CONFIG = "softap_config"; - private static final String KEY_NETWORK_POLICIES = "network_policies"; - private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; - private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config"; - private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings"; - // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a - // fatal crash. Creating a backup with a different key will prevent Android 12 versions from - // restoring this data. - private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2"; - private static final String KEY_WIFI_SETTINGS_BACKUP_DATA = "wifi_settings_backup_data"; - // Versioning of the state file. Increment this version // number any time the set of state items is altered. private static final int STATE_VERSION = 9; @@ -257,6 +254,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); if (com.android.server.backup.Flags.enableMetricsSettingsBackupAgents()) { mBackupRestoreEventLogger = this.getBackupRestoreEventLogger(); + mSettingsHelper.setBackupRestoreEventLogger(mBackupRestoreEventLogger); numberOfSettingsPerKey = new HashMap<>(); areAgentMetricsEnabled = true; } @@ -412,9 +410,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { mSettingsHelper .setLocaleData( localeData, - size, - mBackupRestoreEventLogger, - KEY_LOCALE); + size); break; case KEY_WIFI_CONFIG : @@ -552,8 +548,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (nBytes > buffer.length) buffer = new byte[nBytes]; in.readFully(buffer, 0, nBytes); mSettingsHelper - .setLocaleData( - buffer, nBytes, mBackupRestoreEventLogger, KEY_LOCALE); + .setLocaleData(buffer, nBytes); // Restore older backups performing the necessary migrations. if (version < FULL_BACKUP_ADDED_WIFI_NEW) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java new file mode 100644 index 000000000000..745c2fb5409d --- /dev/null +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupRestoreKeys.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.providers.settings; + +import android.net.Uri; +import android.provider.Settings; + +/** + * Class to store the keys used for backup and restore. + */ +final class SettingsBackupRestoreKeys { + static final String KEY_UNKNOWN = "unknown"; + static final String KEY_SYSTEM = "system"; + static final String KEY_SECURE = "secure"; + static final String KEY_GLOBAL = "global"; + static final String KEY_LOCALE = "locale"; + static final String KEY_LOCK_SETTINGS = "lock_settings"; + static final String KEY_SOFTAP_CONFIG = "softap_config"; + static final String KEY_NETWORK_POLICIES = "network_policies"; + static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; + static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config"; + static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings"; + // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a + // fatal crash. Creating a backup with a different key will prevent Android 12 versions from + // restoring this data. + static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2"; + static final String KEY_WIFI_SETTINGS_BACKUP_DATA = "wifi_settings_backup_data"; + + /** + * Returns the key corresponding to the given URI. + * + * @param uri The URI of the setting's destination. + * @return The key corresponding to the given URI, or KEY_UNKNOWN if the URI is not recognized. + */ + static String getKeyFromUri(Uri uri) { + if (uri.equals(Settings.Secure.CONTENT_URI)) { + return KEY_SECURE; + } else if (uri.equals(Settings.System.CONTENT_URI)) { + return KEY_SYSTEM; + } else if (uri.equals(Settings.Global.CONTENT_URI)) { + return KEY_GLOBAL; + } else { + return KEY_UNKNOWN; + } + } + +}
\ No newline at end of file diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index 924c151a99a0..ab8d739feb43 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -17,6 +17,7 @@ package com.android.providers.settings; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.backup.BackupRestoreEventLogger; @@ -84,6 +85,7 @@ public class SettingsHelper { private Context mContext; private AudioManager mAudioManager; private TelephonyManager mTelephonyManager; + @Nullable private BackupRestoreEventLogger mBackupRestoreEventLogger; /** * A few settings elements are special in that a restore of those values needs to @@ -741,11 +743,8 @@ public class SettingsHelper { * * @param data the comma separated BCP-47 language tags in bytes. * @param size the size of the data in bytes. - * @param backupRestoreEventLogger the logger to log the restore event. - * @param dataType the data type of the setting for logging purposes. */ - /* package */ void setLocaleData( - byte[] data, int size, BackupRestoreEventLogger backupRestoreEventLogger, String dataType) { + /* package */ void setLocaleData(byte[] data, int size) { final Configuration conf = mContext.getResources().getConfiguration(); // Replace "_" with "-" to deal with older backups. @@ -772,15 +771,15 @@ public class SettingsHelper { am.updatePersistentConfigurationWithAttribution(config, mContext.getOpPackageName(), mContext.getAttributionTag()); - if (Flags.enableMetricsSettingsBackupAgents()) { - backupRestoreEventLogger - .logItemsRestored(dataType, localeList.size()); + if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) { + mBackupRestoreEventLogger + .logItemsRestored(SettingsBackupRestoreKeys.KEY_LOCALE, localeList.size()); } } catch (RemoteException e) { - if (Flags.enableMetricsSettingsBackupAgents()) { - backupRestoreEventLogger + if (Flags.enableMetricsSettingsBackupAgents() && mBackupRestoreEventLogger != null) { + mBackupRestoreEventLogger .logItemsRestoreFailed( - dataType, + SettingsBackupRestoreKeys.KEY_LOCALE, localeList.size(), ERROR_REMOTE_EXCEPTION_SETTING_LOCALE_DATA); } @@ -795,4 +794,13 @@ public class SettingsHelper { AudioManager am = new AudioManager(mContext); am.reloadAudioSettings(); } + + /** + * Sets the backup restore event logger. + * + * @param backupRestoreEventLogger the logger to log B&R metrics. + */ + void setBackupRestoreEventLogger(BackupRestoreEventLogger backupRestoreEventLogger) { + mBackupRestoreEventLogger = backupRestoreEventLogger; + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index f9c64422b0db..661a09553914 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -2520,6 +2520,13 @@ class SettingsProtoDumpUtil { Settings.Secure.RTT_CALLING_MODE, SecureSettingsProto.RTT_CALLING_MODE); + final long screenoffudfpsenabledToken = p.start( + SecureSettingsProto.SCREEN_OFF_UDFPS_ENABLED); + dumpSetting(s, p, + Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED, + SecureSettingsProto.SCREEN_OFF_UDFPS_ENABLED); + p.end(screenoffudfpsenabledToken); + final long screensaverToken = p.start(SecureSettingsProto.SCREENSAVER); dumpSetting(s, p, Settings.Secure.SCREENSAVER_ENABLED, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 55f48e3e367f..f1f03c31f718 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -120,6 +120,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.display.RefreshRateSettingsUtils; import com.android.internal.os.BackgroundThread; @@ -2914,6 +2915,14 @@ public class SettingsProvider extends ContentProvider { }; } + @VisibleForTesting + void injectServices(UserManager userManager, IPackageManager packageManager, + SystemConfigManager sysConfigManager) { + mUserManager = userManager; + mPackageManager = packageManager; + mSysConfigManager = sysConfigManager; + } + private static final class Arguments { private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS = Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*"); @@ -3080,6 +3089,7 @@ public class SettingsProvider extends ContentProvider { private static final String SSAID_USER_KEY = "userkey"; + @GuardedBy("mLock") private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>(); private GenerationRegistry mGenerationRegistry; @@ -3992,6 +4002,14 @@ public class SettingsProvider extends ContentProvider { } } + @VisibleForTesting + void injectSettings(SettingsState settings, int type, int userId) { + int key = makeKey(type, userId); + synchronized (mLock) { + mSettingsStates.put(key, settings); + } + } + private final class MyHandler extends Handler { private static final int MSG_NOTIFY_URI_CHANGED = 1; private static final int MSG_NOTIFY_DATA_CHANGED = 2; @@ -4023,12 +4041,21 @@ public class SettingsProvider extends ContentProvider { } } - private final class UpgradeController { + @VisibleForTesting + final class UpgradeController { private static final int SETTINGS_VERSION = 226; private final int mUserId; + private final Injector mInjector; + public UpgradeController(int userId) { + this(/* injector= */ null, userId); + } + + @VisibleForTesting + UpgradeController(Injector injector, int userId) { + mInjector = injector == null ? new Injector() : injector; mUserId = userId; } @@ -6136,8 +6163,8 @@ public class SettingsProvider extends ContentProvider { systemSettings.getSettingLocked(Settings.System.PEAK_REFRESH_RATE); final Setting minRefreshRateSetting = systemSettings.getSettingLocked(Settings.System.MIN_REFRESH_RATE); - float highestRefreshRate = RefreshRateSettingsUtils - .findHighestRefreshRateForDefaultDisplay(getContext()); + float highestRefreshRate = + mInjector.findHighestRefreshRateForDefaultDisplay(getContext()); if (!peakRefreshRateSetting.isNull()) { try { @@ -6318,6 +6345,14 @@ public class SettingsProvider extends ContentProvider { private long getBitMask(int capability) { return 1 << (capability - 1); } + + @VisibleForTesting + static class Injector { + float findHighestRefreshRateForDefaultDisplay(Context context) { + return RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay( + context); + } + } } /** diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 5cd534e62ea9..bf3afeda448e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -107,7 +107,7 @@ import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon; * the same lock to grab the current state to write to disk. * </p> */ -final class SettingsState { +public class SettingsState { private static final boolean DEBUG = false; private static final boolean DEBUG_PERSISTENCE = false; @@ -1838,7 +1838,7 @@ final class SettingsState { } } - class Setting { + public class Setting { private String name; private String value; private String defaultValue; diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java new file mode 100644 index 000000000000..ef537e8c7fc0 --- /dev/null +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupRestoreKeysTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.providers.settings; + +import static com.google.common.truth.Truth.assertThat; + +import android.net.Uri; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link SettingsBackupRestoreKeys}. + */ +@RunWith(AndroidJUnit4.class) +public class SettingsBackupRestoreKeysTest { + + @Test + public void getKeyFromUri_secureUri_returnsSecureKey() { + assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.Secure.CONTENT_URI)) + .isEqualTo(SettingsBackupRestoreKeys.KEY_SECURE); + } + + @Test + public void getKeyFromUri_systemUri_returnsSystemKey() { + assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.System.CONTENT_URI)) + .isEqualTo(SettingsBackupRestoreKeys.KEY_SYSTEM); + } + + @Test + public void getKeyFromUri_globalUri_returnsGlobalKey() { + assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Settings.Global.CONTENT_URI)) + .isEqualTo(SettingsBackupRestoreKeys.KEY_GLOBAL); + } + + @Test + public void getKeyFromUri_unknownUri_returnsUnknownKey() { + assertThat(SettingsBackupRestoreKeys.getKeyFromUri(Uri.parse("content://unknown"))) + .isEqualTo(SettingsBackupRestoreKeys.KEY_UNKNOWN); + } +}
\ No newline at end of file diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java index 9cce43160b52..119b2870b622 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java @@ -16,7 +16,7 @@ package com.android.providers.settings; -import static android.provider.Settings.Secure.ACCESSIBILITY_ENABLED; +import static android.provider.Settings.Secure.CONTENT_CAPTURE_ENABLED; import static android.provider.Settings.Secure.SYNC_PARENT_SOUNDS; import static android.provider.Settings.System.RINGTONE; @@ -67,7 +67,7 @@ public class SettingsProviderMultiUsersTest { private static final String SPACE_SYSTEM = "system"; private static final String SPACE_SECURE = "secure"; - private static final String CLONE_TO_MANAGED_PROFILE_SETTING = ACCESSIBILITY_ENABLED; + private static final String CLONE_TO_MANAGED_PROFILE_SETTING = CONTENT_CAPTURE_ENABLED; private static final String CLONE_FROM_PARENT_SETTINGS = RINGTONE; private static final String SYNC_FROM_PARENT_SETTINGS = SYNC_PARENT_SOUNDS; diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java new file mode 100644 index 000000000000..26ff376f828e --- /dev/null +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/UpgradeControllerTest.java @@ -0,0 +1,175 @@ +/* + * 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.providers.settings; + +import static android.provider.Settings.System.MIN_REFRESH_RATE; +import static android.provider.Settings.System.PEAK_REFRESH_RATE; + +import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_GLOBAL; +import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_SECURE; +import static com.android.providers.settings.SettingsProvider.SETTINGS_TYPE_SYSTEM; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.IPackageManager; +import android.os.Looper; +import android.os.SystemConfigManager; +import android.os.UserHandle; +import android.os.UserManager; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class UpgradeControllerTest { + private static final int USER_ID = UserHandle.USER_SYSTEM; + private static final float HIGHEST_REFRESH_RATE = 130f; + + private final Context mContext = + spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + private final SettingsProvider.SettingsRegistry.UpgradeController.Injector mInjector = + new SettingsProvider.SettingsRegistry.UpgradeController.Injector() { + @Override + float findHighestRefreshRateForDefaultDisplay(Context context) { + return HIGHEST_REFRESH_RATE; + } + }; + private final SettingsProvider mSettingsProvider = new SettingsProvider() { + @Override + public boolean onCreate() { + return true; + } + }; + private final SettingsProvider.SettingsRegistry mSettingsRegistry = + mSettingsProvider.new SettingsRegistry(Looper.getMainLooper()); + private final SettingsProvider.SettingsRegistry.UpgradeController mUpgradeController = + mSettingsRegistry.new UpgradeController(mInjector, USER_ID); + + @Mock + private UserManager mUserManager; + + @Mock + private IPackageManager mPackageManager; + + @Mock + private SystemConfigManager mSysConfigManager; + + @Mock + private SettingsState mSystemSettings; + + @Mock + private SettingsState mSecureSettings; + + @Mock + private SettingsState mGlobalSettings; + + @Mock + private SettingsState.Setting mMockSetting; + + @Mock + private SettingsState.Setting mPeakRefreshRateSetting; + + @Mock + private SettingsState.Setting mMinRefreshRateSetting; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSettingsProvider.attachInfoForTesting(mContext, /* info= */ null); + mSettingsProvider.injectServices(mUserManager, mPackageManager, mSysConfigManager); + when(mSystemSettings.getSettingLocked(any())).thenReturn(mMockSetting); + when(mSecureSettings.getSettingLocked(any())).thenReturn(mMockSetting); + when(mGlobalSettings.getSettingLocked(any())).thenReturn(mMockSetting); + when(mMockSetting.isNull()).thenReturn(true); + when(mMockSetting.getValue()).thenReturn("0"); + + when(mSystemSettings.getSettingLocked(PEAK_REFRESH_RATE)) + .thenReturn(mPeakRefreshRateSetting); + when(mSystemSettings.getSettingLocked(MIN_REFRESH_RATE)) + .thenReturn(mMinRefreshRateSetting); + + mSettingsRegistry.injectSettings(mSystemSettings, SETTINGS_TYPE_SYSTEM, USER_ID); + mSettingsRegistry.injectSettings(mSecureSettings, SETTINGS_TYPE_SECURE, USER_ID); + mSettingsRegistry.injectSettings(mGlobalSettings, SETTINGS_TYPE_GLOBAL, USER_ID); + + // Lowest version so that all upgrades are run + when(mSecureSettings.getVersionLocked()).thenReturn(118); + } + + @Test + public void testUpgrade_refreshRateSettings_defaultValues() { + when(mPeakRefreshRateSetting.isNull()).thenReturn(true); + when(mMinRefreshRateSetting.isNull()).thenReturn(true); + + mUpgradeController.upgradeIfNeededLocked(); + + // Should remain unchanged + verify(mSystemSettings, never()).insertSettingLocked(eq(PEAK_REFRESH_RATE), + /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(), + /* packageName= */ any()); + verify(mSystemSettings, never()).insertSettingLocked(eq(MIN_REFRESH_RATE), + /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(), + /* packageName= */ any()); + } + + @Test + public void testUpgrade_refreshRateSettings_enabled() { + when(mPeakRefreshRateSetting.isNull()).thenReturn(false); + when(mMinRefreshRateSetting.isNull()).thenReturn(false); + when(mPeakRefreshRateSetting.getValue()).thenReturn(String.valueOf(HIGHEST_REFRESH_RATE)); + when(mMinRefreshRateSetting.getValue()).thenReturn(String.valueOf(HIGHEST_REFRESH_RATE)); + + mUpgradeController.upgradeIfNeededLocked(); + + // Highest refresh rate gets converted to infinity + verify(mSystemSettings).insertSettingLocked(eq(PEAK_REFRESH_RATE), + eq(String.valueOf(Float.POSITIVE_INFINITY)), /* tag= */ any(), + /* makeDefault= */ anyBoolean(), /* packageName= */ any()); + verify(mSystemSettings).insertSettingLocked(eq(MIN_REFRESH_RATE), + eq(String.valueOf(Float.POSITIVE_INFINITY)), /* tag= */ any(), + /* makeDefault= */ anyBoolean(), /* packageName= */ any()); + } + + @Test + public void testUpgrade_refreshRateSettings_disabled() { + when(mPeakRefreshRateSetting.isNull()).thenReturn(false); + when(mMinRefreshRateSetting.isNull()).thenReturn(false); + when(mPeakRefreshRateSetting.getValue()).thenReturn("70f"); + when(mMinRefreshRateSetting.getValue()).thenReturn("70f"); + + mUpgradeController.upgradeIfNeededLocked(); + + // Should remain unchanged + verify(mSystemSettings, never()).insertSettingLocked(eq(PEAK_REFRESH_RATE), + /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(), + /* packageName= */ any()); + verify(mSystemSettings, never()).insertSettingLocked(eq(MIN_REFRESH_RATE), + /* value= */ any(), /* tag= */ any(), /* makeDefault= */ anyBoolean(), + /* packageName= */ any()); + } +} diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index fb4293a9b5ea..46bd88fcdc93 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -994,6 +994,9 @@ <uses-permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> + <!-- Permission required for CTS test - CtsContentProviderMultiUserTest --> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 3d250fd82473..3ee2db10d7e5 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -85,6 +85,7 @@ filegroup { filegroup { name: "SystemUI-tests-broken-robofiles-run", srcs: [ + "tests/src/**/systemui/dreams/touch/CommunalTouchHandlerTest.java", "tests/src/**/systemui/shade/NotificationShadeWindowViewControllerTest.kt", "tests/src/**/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt", "tests/src/**/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt", @@ -269,7 +270,7 @@ filegroup { "tests/src/**/systemui/stylus/StylusManagerTest.kt", "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt", "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt", - "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt", + "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt", "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java", "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt", "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java", @@ -418,6 +419,9 @@ android_library { "androidx.slice_slice-view", ], manifest: "AndroidManifest-res.xml", + flags_packages: [ + "com_android_systemui_flags", + ], } android_library { diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 1b1c91de1e56..e02bd9e71292 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -496,6 +496,13 @@ flag { } flag { + name: "status_bar_popup_chips" + namespace: "systemui" + description: "Show rich ongoing processes as chips in the status bar" + bug: "372964148" +} + +flag { name: "promote_notifications_automatically" namespace: "systemui" description: "Flag to automatically turn certain notifications into promoted notifications so " @@ -1229,6 +1236,21 @@ flag { } flag { + name: "glanceable_hub_v2_resources" + namespace: "systemui" + description: "Read only flag for rolling out glanceable hub v2 resource values" + bug: "375689917" + is_fixed_read_only: true +} + +flag { + name: "glanceable_hub_back_action" + namespace: "systemui" + description: "Support back action from glanceable hub" + bug: "382771533" +} + +flag { name: "dream_overlay_updated_font" namespace: "systemui" description: "Flag to enable updated font settings for dream overlay" @@ -1882,3 +1904,10 @@ flag { description: "Invokes edit mode directly from long press in glanceable hub" bug: "382531177" } + +flag { + name: "notification_magic_actions_treatment" + namespace: "systemui" + description: "Special UI treatment for magic actions" + bug: "383567383" +} diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java index ca2b9578f2be..7d27a562f536 100644 --- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java +++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java @@ -195,7 +195,10 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { // Create the origin leash and add to the transition root leash. mOriginLeash = new SurfaceControl.Builder().setName("OriginTransition-origin-leash").build(); - mStartTransaction + + // Create temporary transaction to build + final SurfaceControl.Transaction tmpTransaction = new SurfaceControl.Transaction(); + tmpTransaction .reparent(mOriginLeash, rootLeash) .show(mOriginLeash) .setCornerRadius(mOriginLeash, windowRadius) @@ -208,14 +211,14 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { int mode = change.getMode(); SurfaceControl leash = change.getLeash(); // Reparent leash to the transition root. - mStartTransaction.reparent(leash, rootLeash); + tmpTransaction.reparent(leash, rootLeash); if (TransitionUtil.isOpeningMode(mode)) { openingSurfaces.add(change.getLeash()); // For opening surfaces, ending bounds are base bound. Apply corner radius if // it's full screen. Rect bounds = change.getEndAbsBounds(); if (displayBounds.equals(bounds)) { - mStartTransaction + tmpTransaction .setCornerRadius(leash, windowRadius) .setWindowCrop(leash, bounds.width(), bounds.height()); } @@ -226,28 +229,53 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { // it's full screen. Rect bounds = change.getStartAbsBounds(); if (displayBounds.equals(bounds)) { - mStartTransaction + tmpTransaction .setCornerRadius(leash, windowRadius) .setWindowCrop(leash, bounds.width(), bounds.height()); } } } + if (openingSurfaces.isEmpty() && closingSurfaces.isEmpty()) { + logD("prepareUIs: no opening/closing surfaces available, nothing to prepare."); + return false; + } + // Set relative order: // ---- App1 ---- // ---- origin ---- // ---- App2 ---- + if (mIsEntry) { - mStartTransaction - .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1) - .setRelativeLayer( - openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1); + if (!closingSurfaces.isEmpty()) { + tmpTransaction + .setRelativeLayer(mOriginLeash, closingSurfaces.get(0), 1); + } else { + logW("Missing closing surface is entry transition"); + } + if (!openingSurfaces.isEmpty()) { + tmpTransaction + .setRelativeLayer( + openingSurfaces.get(openingSurfaces.size() - 1), mOriginLeash, 1); + } else { + logW("Missing opening surface is entry transition"); + } + } else { - mStartTransaction - .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1) - .setRelativeLayer( - closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1); + if (!openingSurfaces.isEmpty()) { + tmpTransaction + .setRelativeLayer(mOriginLeash, openingSurfaces.get(0), 1); + } else { + logW("Missing opening surface is exit transition"); + } + if (!closingSurfaces.isEmpty()) { + tmpTransaction.setRelativeLayer( + closingSurfaces.get(closingSurfaces.size() - 1), mOriginLeash, 1); + } else { + logW("Missing closing surface is exit transition"); + } } + mStartTransaction.merge(tmpTransaction); // Attach origin UIComponent to origin leash. mOriginTransaction = mOrigin.newTransaction(); @@ -300,6 +328,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { } private void cancel() { + logD("cancel()"); if (mAnimator != null) { mAnimator.cancel(); } @@ -311,6 +340,10 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub { } } + private static void logW(String msg) { + Log.w(TAG, msg); + } + private static void logE(String msg) { Log.e(TAG, msg); } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt index 41a00f5237f7..b0c7ac09551a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt @@ -17,7 +17,6 @@ package com.android.systemui.animation import android.app.ActivityManager -import android.app.ActivityOptions import android.app.ActivityTaskManager import android.app.PendingIntent import android.app.TaskInfo @@ -292,7 +291,7 @@ constructor( ?: throw IllegalStateException( "ActivityTransitionAnimator.callback must be set before using this animator" ) - val runner = createRunner(controller) + val runner = createEphemeralRunner(controller) val runnerDelegate = runner.delegate val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen @@ -416,7 +415,7 @@ constructor( var cleanUpRunnable: Runnable? = null val returnRunner = - createRunner( + createEphemeralRunner( object : DelegateTransitionAnimatorController(launchController) { override val isLaunching = false @@ -458,11 +457,7 @@ constructor( "${launchController.transitionCookie}_returnTransition", ) - transitionRegister?.register( - filter, - transition, - includeTakeover = longLivedReturnAnimationsEnabled(), - ) + transitionRegister?.register(filter, transition, includeTakeover = false) cleanUpRunnable = Runnable { transitionRegister?.unregister(transition) } } @@ -476,12 +471,14 @@ constructor( listeners.remove(listener) } - /** Create a new animation [Runner] controlled by [controller]. */ + /** + * Create a new animation [Runner] controlled by [controller]. + * + * This method must only be used for ephemeral (launch or return) transitions. Otherwise, use + * [createLongLivedRunner]. + */ @VisibleForTesting - @JvmOverloads - fun createRunner(controller: Controller, longLived: Boolean = false): Runner { - if (longLived) assertLongLivedReturnAnimations() - + fun createEphemeralRunner(controller: Controller): Runner { // Make sure we use the modified timings when animating a dialog into an app. val transitionAnimator = if (controller.isDialogLaunch) { @@ -490,7 +487,22 @@ constructor( transitionAnimator } - return Runner(controller, callback!!, transitionAnimator, lifecycleListener, longLived) + return Runner(controller, callback!!, transitionAnimator, lifecycleListener) + } + + /** + * Create a new animation [Runner] controlled by the [Controller] that [controllerFactory] can + * create based on [forLaunch]. + * + * This method must only be used for long-lived registrations. Otherwise, use + * [createEphemeralRunner]. + */ + @VisibleForTesting + fun createLongLivedRunner(controllerFactory: ControllerFactory, forLaunch: Boolean): Runner { + assertLongLivedReturnAnimations() + return Runner(callback!!, transitionAnimator, lifecycleListener) { + controllerFactory.createController(forLaunch) + } } interface PendingIntentStarter { @@ -537,6 +549,23 @@ constructor( } /** + * A factory used to create instances of [Controller] linked to a specific cookie [cookie] and + * [component]. + */ + abstract class ControllerFactory( + val cookie: TransitionCookie, + val component: ComponentName?, + val launchCujType: Int? = null, + val returnCujType: Int? = null, + ) { + /** + * Creates a [Controller] for launching or returning from the activity linked to [cookie] + * and [component]. + */ + abstract fun createController(forLaunch: Boolean): Controller + } + + /** * A controller that takes care of applying the animation to an expanding view. * * Note that all callbacks (onXXX methods) are all called on the main thread. @@ -656,13 +685,13 @@ constructor( } /** - * Registers [controller] as a long-lived transition handler for launch and return animations. + * Registers [controllerFactory] as a long-lived transition handler for launch and return + * animations. * - * The [controller] will only be used for transitions matching the [TransitionCookie] defined - * within it, or the [ComponentName] if the cookie matching fails. Both fields are mandatory for - * this registration. + * The [Controller]s created by [controllerFactory] will only be used for transitions matching + * the [cookie], or the [ComponentName] defined within it if the cookie matching fails. */ - fun register(controller: Controller) { + fun register(cookie: TransitionCookie, controllerFactory: ControllerFactory) { assertLongLivedReturnAnimations() if (transitionRegister == null) { @@ -672,13 +701,8 @@ constructor( ) } - val cookie = - controller.transitionCookie - ?: throw IllegalStateException( - "A cookie must be defined in order to use long-lived animations" - ) val component = - controller.component + controllerFactory.component ?: throw IllegalStateException( "A component must be defined in order to use long-lived animations" ) @@ -699,15 +723,11 @@ constructor( } val launchRemoteTransition = RemoteTransition( - OriginTransition(createRunner(controller, longLived = true)), + OriginTransition(createLongLivedRunner(controllerFactory, forLaunch = true)), "${cookie}_launchTransition", ) transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true) - val returnController = - object : Controller by controller { - override val isLaunching: Boolean = false - } // Cross-task close transitions should not use this animation, so we only register it for // when the opening window is Launcher. val returnFilter = @@ -727,7 +747,7 @@ constructor( } val returnRemoteTransition = RemoteTransition( - OriginTransition(createRunner(returnController, longLived = true)), + OriginTransition(createLongLivedRunner(controllerFactory, forLaunch = false)), "${cookie}_returnTransition", ) transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true) @@ -918,32 +938,61 @@ constructor( } @VisibleForTesting - inner class Runner( + inner class Runner + private constructor( /** * This can hold a reference to a view, so it needs to be cleaned up and can't be held on to - * forever when ![longLived]. + * forever. In case of a long-lived [Runner], this must be null and [controllerFactory] must + * be defined instead. */ private var controller: Controller?, + /** + * Reusable factory to generate single-use controllers. In case of an ephemeral [Runner], + * this must be null and [controller] must be defined instead. + */ + private val controllerFactory: (() -> Controller)?, private val callback: Callback, /** The animator to use to animate the window transition. */ private val transitionAnimator: TransitionAnimator, /** Listener for animation lifecycle events. */ - private val listener: Listener? = null, - /** - * Whether the internal should be kept around after execution for later usage. IMPORTANT: - * should always be false if this [Runner] is to be used directly with [ActivityOptions] - * (i.e. for ephemeral launches), or the controller will leak its view. - */ - private val longLived: Boolean = false, + private val listener: Listener?, ) : IRemoteAnimationRunner.Stub() { + constructor( + controller: Controller, + callback: Callback, + transitionAnimator: TransitionAnimator, + listener: Listener? = null, + ) : this( + controller = controller, + controllerFactory = null, + callback = callback, + transitionAnimator = transitionAnimator, + listener = listener, + ) + + constructor( + callback: Callback, + transitionAnimator: TransitionAnimator, + listener: Listener? = null, + controllerFactory: () -> Controller, + ) : this( + controller = null, + controllerFactory = controllerFactory, + callback = callback, + transitionAnimator = transitionAnimator, + listener = listener, + ) + // This is being passed across IPC boundaries and cycles (through PendingIntentRecords, // etc.) are possible. So we need to make sure we drop any references that might // transitively cause leaks when we're done with animation. @VisibleForTesting var delegate: AnimationDelegate? init { + assert((controller != null).xor(controllerFactory != null)) + delegate = null - if (!longLived) { + if (controller != null) { // Ephemeral launches bundle the runner with the launch request (instead of being // registered ahead of time for later use). This means that there could be a timeout // between creation and invocation, so the delegate needs to exist from the @@ -1021,17 +1070,21 @@ constructor( @AnyThread private fun maybeSetUp() { - if (!longLived || delegate != null) return + if (controllerFactory == null || delegate != null) return createDelegate() } @AnyThread private fun createDelegate() { - if (controller == null) return + var controller = controller + val factory = controllerFactory + if (controller == null && factory == null) return + + controller = controller ?: factory!!.invoke() delegate = AnimationDelegate( mainExecutor, - controller!!, + controller, callback, DelegatingAnimationCompletionListener(listener, this::dispose), transitionAnimator, @@ -1041,13 +1094,12 @@ constructor( @AnyThread fun dispose() { - // Drop references to animation controller once we're done with the animation - // to avoid leaking. + // Drop references to animation controller once we're done with the animation to avoid + // leaking in case of ephemeral launches. When long-lived, [controllerFactory] will + // still be around to create new controllers. mainExecutor.execute { delegate = null - // When long lived, the same Runner can be used more than once. In this case we need - // to keep the controller around so we can rebuild the delegate on demand. - if (!longLived) controller = null + controller = null } } } 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 a17a1d46554f..0a0003ee9a8a 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 @@ -19,17 +19,20 @@ package com.android.systemui.communal.ui.compose import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntRect import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.android.compose.animation.scene.SceneScope +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection import com.android.systemui.communal.ui.compose.section.CommunalPopupSection @@ -39,8 +42,11 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection import com.android.systemui.keyguard.ui.composable.section.LockSection +import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialogFactory import javax.inject.Inject +import kotlin.math.min +import kotlin.math.roundToInt /** Renders the content of the glanceable hub. */ class CommunalContent @@ -48,6 +54,7 @@ class CommunalContent constructor( private val viewModel: CommunalViewModel, private val interactionHandler: SmartspaceInteractionHandler, + private val communalSettingsInteractor: CommunalSettingsInteractor, private val dialogFactory: SystemUIDialogFactory, private val lockSection: LockSection, private val bottomAreaSection: BottomAreaSection, @@ -77,11 +84,20 @@ constructor( sceneScope = this@Content, ) } - with(lockSection) { - LockIcon( - overrideColor = MaterialTheme.colorScheme.onPrimaryContainer, + if (communalSettingsInteractor.isV2FlagEnabled()) { + Icon( + painter = painterResource(id = R.drawable.ic_lock), + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimaryContainer, modifier = Modifier.element(Communal.Elements.LockIcon), ) + } else { + with(lockSection) { + LockIcon( + overrideColor = MaterialTheme.colorScheme.onPrimaryContainer, + modifier = Modifier.element(Communal.Elements.LockIcon), + ) + } } with(bottomAreaSection) { IndicationArea( @@ -98,14 +114,42 @@ constructor( val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0) - val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconPlaceable = + if (communalSettingsInteractor.isV2FlagEnabled()) { + val lockIconSizeInt = lockIconSize.roundToPx() + lockIconMeasurable.measure( + Constraints.fixed(width = lockIconSizeInt, height = lockIconSizeInt) + ) + } else { + lockIconMeasurable.measure(noMinConstraints) + } val lockIconBounds = - IntRect( - left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], - top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], - right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], - bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], - ) + if (communalSettingsInteractor.isV2FlagEnabled()) { + val lockIconDistanceFromBottom = + min( + (constraints.maxHeight * lockIconPercentDistanceFromBottom) + .roundToInt(), + lockIconMinDistanceFromBottom.roundToPx(), + ) + val x = constraints.maxWidth / 2 - lockIconPlaceable.width / 2 + val y = + constraints.maxHeight - + lockIconDistanceFromBottom - + lockIconPlaceable.height + IntRect( + left = x, + top = y, + right = x + lockIconPlaceable.width, + bottom = y + lockIconPlaceable.height, + ) + } else { + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + } val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) @@ -129,12 +173,17 @@ constructor( val bottomAreaTop = constraints.maxHeight - bottomAreaPlaceable.height bottomAreaPlaceable.place(x = 0, y = bottomAreaTop) + + val screensaverButtonPaddingInt = screensaverButtonPadding.roundToPx() screensaverButtonPlaceable?.place( x = constraints.maxWidth - screensaverButtonSizeInt - - Dimensions.ItemSpacing.roundToPx(), - y = lockIconBounds.top, + screensaverButtonPaddingInt, + y = + constraints.maxHeight - + screensaverButtonSizeInt - + screensaverButtonPaddingInt, ) } } @@ -142,6 +191,12 @@ constructor( } companion object { - val screensaverButtonSize: Dp = 64.dp + 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 + // position are sorted. + private val lockIconSize: Dp = 54.dp + private val lockIconPercentDistanceFromBottom = 0.1f + private val lockIconMinDistanceFromBottom = 70.dp } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 5dbedc7045e4..fab0ca318fbf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -931,7 +931,9 @@ private fun BoxScope.CommunalHubLazyGrid( Modifier.requiredSize(dpSize) .thenIf(!isItemDragging) { Modifier.animateItem( - placementSpec = spring(stiffness = Spring.StiffnessMediumLow) + placementSpec = spring(stiffness = Spring.StiffnessMediumLow), + // See b/376495198 - not supported with AndroidView + fadeOutSpec = null, ) } .thenIf(isItemDragging) { Modifier.zIndex(1f) }, @@ -980,11 +982,14 @@ private fun BoxScope.CommunalHubLazyGrid( size = size, selected = false, modifier = - Modifier.requiredSize(dpSize).animateItem().thenIf( - communalResponsiveGrid() - ) { - Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f } - }, + Modifier.requiredSize(dpSize) + .animateItem( + // See b/376495198 - not supported with AndroidView + fadeOutSpec = null + ) + .thenIf(communalResponsiveGrid()) { + Modifier.graphicsLayer { alpha = itemAlpha?.value ?: 1f } + }, index = index, contentListState = contentListState, interactionHandler = interactionHandler, @@ -1005,8 +1010,11 @@ private fun EmptyStateCta(contentPadding: PaddingValues, viewModel: BaseCommunal val colors = MaterialTheme.colorScheme Card( modifier = Modifier.height(hubDimensions.GridHeight).padding(contentPadding), - colors = CardDefaults.cardColors(containerColor = Color.Transparent), - border = BorderStroke(3.adjustedDp, colors.secondary), + colors = + CardDefaults.cardColors( + containerColor = colors.primary, + contentColor = colors.onPrimary, + ), shape = RoundedCornerShape(size = 80.adjustedDp), ) { Column( @@ -1027,13 +1035,14 @@ private fun EmptyStateCta(contentPadding: PaddingValues, viewModel: BaseCommunal heading() }, ) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Button( modifier = Modifier.height(56.dp), colors = ButtonDefaults.buttonColors( - containerColor = colors.primary, - contentColor = colors.onPrimary, + containerColor = colors.primaryContainer, + contentColor = colors.onPrimaryContainer, ), onClick = { viewModel.onOpenWidgetEditor(shouldOpenWidgetPickerOnStart = true) }, ) { 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 5c7ca97474b7..0344ab8e0196 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 @@ -38,7 +38,6 @@ import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.thenIf import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn import com.android.systemui.keyguard.ui.composable.modifier.burnInAware @@ -90,14 +89,10 @@ constructor( ) { init { - if (!MigrateClocksToBlueprint.isEnabled) { - throw IllegalStateException("this requires MigrateClocksToBlueprint.isEnabled") - } // This scene container section moves the NSSL to the SharedNotificationContainer. // This also requires that SharedNotificationContainer gets moved to the // SceneWindowRootView by the SceneWindowRootViewBinder. Prior to Scene Container, - // but when the KeyguardShadeMigrationNssl flag is enabled, NSSL is moved into this - // container by the NotificationStackScrollLayoutSection. + // NSSL is moved into this container by the NotificationStackScrollLayoutSection. // Ensure stackScrollLayout is a child of sharedNotificationContainer. if (stackScrollLayout.parent != sharedNotificationContainer) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt index db33e7c628d7..79cf24b9c547 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt @@ -35,9 +35,8 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.MutableSceneTransitionLayoutState -import com.android.compose.animation.scene.SceneScope -import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.modifiers.thenIf import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.largeClockScene @@ -61,7 +60,7 @@ constructor( private val clockInteractor: KeyguardClockInteractor, ) { @Composable - fun SceneScope.DefaultClockLayout( + fun ContentScope.DefaultClockLayout( smartSpacePaddingTop: (Resources) -> Int, isShadeLayoutWide: Boolean, modifier: Modifier = Modifier, @@ -95,7 +94,7 @@ constructor( } Column(modifier) { - SceneTransitionLayout(state) { + NestedSceneTransitionLayout(state, Modifier) { scene(splitShadeLargeClockScene) { LargeClockWithSmartSpace( smartSpacePaddingTop = smartSpacePaddingTop, @@ -134,7 +133,7 @@ constructor( } @Composable - private fun SceneScope.SmallClockWithSmartSpace( + private fun ContentScope.SmallClockWithSmartSpace( smartSpacePaddingTop: (Resources) -> Int, modifier: Modifier = Modifier, ) { @@ -159,7 +158,7 @@ constructor( } @Composable - private fun SceneScope.LargeClockWithSmartSpace( + private fun ContentScope.LargeClockWithSmartSpace( smartSpacePaddingTop: (Resources) -> Int, shouldOffSetClockToOneHalf: Boolean = false, ) { @@ -200,7 +199,7 @@ constructor( } @Composable - private fun SceneScope.WeatherLargeClockWithSmartSpace( + private fun ContentScope.WeatherLargeClockWithSmartSpace( smartSpacePaddingTop: (Resources) -> Int, modifier: Modifier = Modifier, ) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt index 2af5ffaee7ed..5790c4af0d77 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt @@ -19,6 +19,7 @@ package com.android.systemui.notifications.ui.composable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.layoutId import com.android.compose.animation.scene.ContentScope @@ -84,7 +85,11 @@ constructor( viewModel.notificationsPlaceholderViewModelFactory.create() } - OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) { + OverlayShade( + panelAlignment = Alignment.TopStart, + modifier = modifier, + onScrimClicked = viewModel::onScrimClicked, + ) { Column { if (viewModel.showHeader) { val burnIn = rememberBurnIn(clockInteractor) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt index b1a19456ab7d..f6c5f588aa95 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt @@ -99,7 +99,11 @@ constructor( val viewModel = rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() } - OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) { + OverlayShade( + panelAlignment = Alignment.TopEnd, + modifier = modifier, + onScrimClicked = viewModel::onScrimClicked, + ) { Column { ExpandedShadeHeader( viewModelFactory = viewModel.shadeHeaderViewModelFactory, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt index 55fafd5cfeca..8907aec7fd48 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.gestures.Orientation import com.android.compose.animation.scene.ProgressConverter import com.android.compose.animation.scene.TransitionKey import com.android.compose.animation.scene.transitions -import com.android.systemui.bouncer.ui.composable.Bouncer import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes @@ -110,17 +109,13 @@ val SceneContainerTransitions = transitions { // Overlay transitions - // TODO(b/376659778): Remove this transition once nested STLs are supported. - from(Scenes.Gone, to = Overlays.NotificationsShade) { - toNotificationsShadeTransition(translateClock = true) - } to(Overlays.NotificationsShade) { toNotificationsShadeTransition() } to(Overlays.QuickSettingsShade) { toQuickSettingsShadeTransition() } from(Overlays.NotificationsShade, to = Overlays.QuickSettingsShade) { notificationsShadeToQuickSettingsShadeTransition() } from(Scenes.Gone, to = Overlays.NotificationsShade, key = SlightlyFasterShadeCollapse) { - toNotificationsShadeTransition(translateClock = true, durationScale = 0.9) + toNotificationsShadeTransition(durationScale = 0.9) } from(Scenes.Gone, to = Overlays.QuickSettingsShade, key = SlightlyFasterShadeCollapse) { toQuickSettingsShadeTransition(durationScale = 0.9) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt index 6bdb36331709..3d62151baf2f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt @@ -29,10 +29,7 @@ import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.Shade import kotlin.time.Duration.Companion.milliseconds -fun TransitionBuilder.toNotificationsShadeTransition( - translateClock: Boolean = false, - durationScale: Double = 1.0, -) { +fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) swipeSpec = spring( @@ -45,11 +42,6 @@ fun TransitionBuilder.toNotificationsShadeTransition( elevateInContent = Overlays.NotificationsShade, ) scaleSize(OverlayShade.Elements.Panel, height = 0f) - // TODO(b/376659778): This is a temporary hack to have a shared element transition with the - // lockscreen clock. Remove once nested STLs are supported. - if (!translateClock) { - translate(ClockElementKeys.smallClockElementKey) - } // Avoid translating the status bar with the shade panel. translate(NotificationsShade.Elements.StatusBar) // Slide in the shade panel from the top edge. diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt index 8a5c96da5ac6..cfbe6671db02 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt @@ -20,6 +20,9 @@ package com.android.systemui.shade.ui.composable import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.rememberScrollableState +import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.PaddingValues @@ -41,30 +44,51 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker -import com.android.compose.animation.scene.SceneScope +import com.android.compose.animation.scene.effect.rememberOffsetOverscrollEffect import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.res.R /** Renders a lightweight shade UI container, as an overlay. */ @Composable -fun SceneScope.OverlayShade( +fun ContentScope.OverlayShade( + panelAlignment: Alignment, onScrimClicked: () -> Unit, modifier: Modifier = Modifier, content: @Composable () -> Unit, ) { - Box(modifier) { + // TODO(b/384653288) This should be removed when b/378470603 is done. + val idleEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) + Box( + modifier + .overscroll(idleEffect) + .nestedScroll( + remember { + object : NestedScrollConnection { + override suspend fun onPreFling(available: Velocity): Velocity { + return available + } + } + } + ) + .scrollable(rememberScrollableState { 0f }, Orientation.Vertical, idleEffect) + ) { Scrim(onClicked = onScrimClicked) - Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) { + Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = panelAlignment) { Panel( modifier = Modifier.element(OverlayShade.Elements.Panel) @@ -77,7 +101,7 @@ fun SceneScope.OverlayShade( } @Composable -private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) { +private fun ContentScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) { Spacer( modifier = modifier @@ -89,7 +113,7 @@ private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifie } @Composable -private fun SceneScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) { +private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) { Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) { Spacer( modifier = @@ -180,7 +204,6 @@ object OverlayShade { object Dimensions { val PanelCornerRadius = 46.dp - val OverscrollLimit = 32.dp } object Shapes { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt index fa5f72bc0997..1480db9de701 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt @@ -37,12 +37,14 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.CustomAccessibilityAction @@ -66,6 +68,10 @@ import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState +import kotlin.math.round +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map @Composable fun VolumeSlider( @@ -196,9 +202,17 @@ private fun LegacyVolumeSlider( ) } } - - // Perform haptics due to UI composition - hapticsViewModel?.onValueChange(value) + var lastDiscreteStep by remember { mutableFloatStateOf(round(value)) } + LaunchedEffect(value) { + snapshotFlow { value } + .map { round(it) } + .filter { it != lastDiscreteStep } + .distinctUntilChanged() + .collect { discreteStep -> + lastDiscreteStep = discreteStep + hapticsViewModel?.onValueChange(discreteStep) + } + } PlatformSlider( modifier = diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index 974442494181..141736f46ee4 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -29,6 +29,7 @@ import com.android.compose.nestedscroll.PriorityNestedScrollConnection import com.android.compose.nestedscroll.ScrollController import com.android.compose.ui.util.SpaceVectorConverter import kotlin.math.absoluteValue +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -359,13 +360,24 @@ private class DragControllerImpl( return swipeAnimation.animateOffset(velocity, targetContent) } - overscrollEffect.applyToFling( - velocity = velocity.toVelocity(), - performFling = { - val velocityLeft = it.toFloat() - swipeAnimation.animateOffset(velocityLeft, targetContent).toVelocity() - }, - ) + val overscrollCompletable = CompletableDeferred<Unit>() + try { + overscrollEffect.applyToFling( + velocity = velocity.toVelocity(), + performFling = { + val velocityLeft = it.toFloat() + swipeAnimation + .animateOffset( + velocityLeft, + targetContent, + overscrollCompletable = overscrollCompletable, + ) + .toVelocity() + }, + ) + } finally { + overscrollCompletable.complete(Unit) + } return velocity } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt index 599a152a23bd..167928b38e90 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt @@ -30,7 +30,8 @@ internal fun Element.shouldBeRenderedBy(content: ContentKey): Boolean { // the transition is running. If the [renderAuthority.size] is 1 it means that that this element // is currently composed only in one nesting level, which means that the render authority // is determined by "classic" shared element code. - return renderAuthority.size == 1 || renderAuthority.first() == content + return renderAuthority.size > 0 && + (renderAuthority.size == 1 || renderAuthority.first() == content) } /** 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 5aaeda84edf0..47daa76b61d0 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 @@ -271,7 +271,7 @@ internal class SwipeAnimation<T : ContentKey>( /** The offset animation that animates the offset once the user lifts their finger. */ private var offsetAnimation: Animatable<Float, AnimationVector1D>? by mutableStateOf(null) - private val offsetAnimationRunnable = CompletableDeferred<(suspend () -> Unit)?>() + private val offsetAnimationRunnable = CompletableDeferred<suspend () -> Unit>() val isUserInputOngoing: Boolean get() = offsetAnimation == null @@ -333,6 +333,7 @@ internal class SwipeAnimation<T : ContentKey>( initialVelocity: Float, targetContent: T, spec: AnimationSpec<Float>? = null, + overscrollCompletable: CompletableDeferred<Unit>? = null, ): Float { check(!isAnimatingOffset()) { "SwipeAnimation.animateOffset() can only be called once" } @@ -391,7 +392,12 @@ internal class SwipeAnimation<T : ContentKey>( // detail). if (skipAnimation) { // Unblock the job. - offsetAnimationRunnable.complete(null) + offsetAnimationRunnable.complete { + // Wait for overscroll to finish so that the transition is removed from the STLState + // only after the overscroll is done, to avoid dropping frame right when the user + // lifts their finger and overscroll is animated to 0. + overscrollCompletable?.await() + } return 0f } @@ -450,6 +456,11 @@ internal class SwipeAnimation<T : ContentKey>( // The animation consumed the whole available velocity velocityConsumed.complete(initialVelocity) } + + // Wait for overscroll to finish so that the transition is removed from the STLState + // only after the overscroll is done, to avoid dropping frame right when the user + // lifts their finger and overscroll is animated to 0. + overscrollCompletable?.await() } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index 801a2d6170cc..b76656d78cc4 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -71,7 +71,6 @@ constructor( } var hasCustomPositionUpdatedAnimation: Boolean = false - var migratedClocks: Boolean = false private val time = Calendar.getInstance() @@ -228,11 +227,7 @@ constructor( override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { logger.d("onMeasure") - if ( - migratedClocks && - !isSingleLineInternal && - MeasureSpec.getMode(heightMeasureSpec) == EXACTLY - ) { + if (!isSingleLineInternal && MeasureSpec.getMode(heightMeasureSpec) == EXACTLY) { // Call straight into TextView.setTextSize to avoid setting lastUnconstrainedTextSize val size = min(lastUnconstrainedTextSize, MeasureSpec.getSize(heightMeasureSpec) / 2F) super.setTextSize(COMPLEX_UNIT_PX, size) @@ -248,7 +243,7 @@ constructor( } } - if (migratedClocks && hasCustomPositionUpdatedAnimation) { + if (hasCustomPositionUpdatedAnimation) { // Expand width to avoid clock being clipped during stepping animation val targetWidth = measuredWidth + MeasureSpec.getSize(widthMeasureSpec) / 2 @@ -582,12 +577,10 @@ constructor( } override fun onRtlPropertiesChanged(layoutDirection: Int) { - if (migratedClocks) { - if (layoutDirection == LAYOUT_DIRECTION_RTL) { - textAlignment = TEXT_ALIGNMENT_TEXT_END - } else { - textAlignment = TEXT_ALIGNMENT_TEXT_START - } + if (layoutDirection == LAYOUT_DIRECTION_RTL) { + textAlignment = TEXT_ALIGNMENT_TEXT_END + } else { + textAlignment = TEXT_ALIGNMENT_TEXT_START } super.onRtlPropertiesChanged(layoutDirection) } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index ad9eba841c86..74d595ce65e6 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -20,7 +20,6 @@ import android.graphics.Rect import android.icu.text.NumberFormat import android.util.TypedValue import android.view.LayoutInflater -import android.view.View import android.widget.FrameLayout import androidx.annotation.VisibleForTesting import com.android.systemui.customization.R @@ -55,7 +54,6 @@ class DefaultClockController( private val layoutInflater: LayoutInflater, private val resources: Resources, private val settings: ClockSettings?, - private val migratedClocks: Boolean = false, messageBuffers: ClockMessageBuffers? = null, ) : ClockController { override val smallClock: DefaultClockFaceController @@ -67,7 +65,6 @@ class DefaultClockController( private val burmeseLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese) private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale) - protected var onSecondaryDisplay: Boolean = false override val events: DefaultClockEvents override val config: ClockConfig by lazy { @@ -175,10 +172,7 @@ class DefaultClockController( recomputePadding(targetRegion) } - override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) { - this@DefaultClockController.onSecondaryDisplay = onSecondaryDisplay - recomputePadding(null) - } + override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {} } open fun recomputePadding(targetRegion: Rect?) {} @@ -197,32 +191,11 @@ class DefaultClockController( override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true) init { - view.migratedClocks = migratedClocks view.hasCustomPositionUpdatedAnimation = true animations = LargeClockAnimations(view, 0f, 0f) } - override fun recomputePadding(targetRegion: Rect?) { - if (migratedClocks) { - return - } - // We center the view within the targetRegion instead of within the parent - // view by computing the difference and adding that to the padding. - val lp = view.getLayoutParams() as FrameLayout.LayoutParams - lp.topMargin = - if (onSecondaryDisplay) { - // On the secondary display we don't want any additional top/bottom margin. - 0 - } else { - val parent = view.parent - val yDiff = - if (targetRegion != null && parent is View && parent.isLaidOut()) - targetRegion.centerY() - parent.height / 2f - else 0f - (-0.5f * view.bottom + yDiff).toInt() - } - view.setLayoutParams(lp) - } + override fun recomputePadding(targetRegion: Rect?) {} /** See documentation at [AnimatableClockView.offsetGlyphsForStepClockAnimation]. */ fun offsetGlyphsForStepClockAnimation(fromLeft: Int, direction: Int, fraction: Float) { 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 e8987257bb47..c73e1c33f88a 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 @@ -47,7 +47,6 @@ class DefaultClockProvider( val ctx: Context, val layoutInflater: LayoutInflater, val resources: Resources, - private val migratedClocks: Boolean = false, private val isClockReactiveVariantsEnabled: Boolean = false, ) : ClockProvider { private var messageBuffers: ClockMessageBuffers? = null @@ -83,14 +82,7 @@ class DefaultClockProvider( FLEX_DESIGN, ) } else { - DefaultClockController( - ctx, - layoutInflater, - resources, - settings, - migratedClocks, - messageBuffers, - ) + DefaultClockController(ctx, layoutInflater, resources, settings, messageBuffers) } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt index 21d41ae744a7..4a47f1bc12bf 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt @@ -140,8 +140,8 @@ class FlexClockFaceController( } /** - * targetRegion passed to all customized clock applies counter translationY of - * KeyguardStatusView and keyguard_large_clock_top_margin from default clock + * targetRegion passed to all customized clock applies counter translationY of Keyguard and + * keyguard_large_clock_top_margin from default clock */ override fun onTargetRegionChanged(targetRegion: Rect?) { // When a clock needs to be aligned with screen, like weather clock diff --git a/packages/SystemUI/docs/clock-plugins.md b/packages/SystemUI/docs/clock-plugins.md index fee82dfcf2e3..813038ee81ec 100644 --- a/packages/SystemUI/docs/clock-plugins.md +++ b/packages/SystemUI/docs/clock-plugins.md @@ -43,12 +43,6 @@ present in the source tree, although it will likely be removed in a later patch. SystemUI event dispatchers to the clock controllers. It maintains a set of event listeners, but otherwise attempts to do as little work as possible. It does maintain some state where necessary. -[KeyguardClockSwitchController](../src/com/android/keyguard/KeyguardClockSwitchController.java) is -the primary controller for the [KeyguardClockSwitch](../src/com/android/keyguard/KeyguardClockSwitch.java), -which serves as the view parent within SystemUI. Together they ensure the correct clock (either -large or small) is shown, handle animation between clock sizes, and control some sizing/layout -parameters for the clocks. - ### Creating a custom clock In order to create a custom clock, a partner must: - Write an implementation of ClockProviderPlugin and the subinterfaces relevant to your use-case. diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt index 85bdf9264467..cea1e9600741 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt @@ -163,6 +163,16 @@ class KeyguardDisplayManagerTest : SysuiTestCase() { } @Test + fun testShow_rearDisplayOuterDefaultActive_occluded() { + displayTracker.allDisplays = arrayOf(defaultDisplay, secondaryDisplay) + + whenever(deviceStateHelper.isRearDisplayOuterDefaultActive(secondaryDisplay)) + .thenReturn(true) + whenever(keyguardStateController.isOccluded).thenReturn(true) + verify(presentationFactory, never()).create(eq(secondaryDisplay)) + } + + @Test fun testShow_presentationCreated() { displayTracker.allDisplays = arrayOf(defaultDisplay, secondaryDisplay) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayoutTest.java new file mode 100644 index 000000000000..455329f54864 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayoutTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.hearingaid; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT; +import static com.android.systemui.accessibility.hearingaid.AmbientVolumeLayout.ROTATION_COLLAPSED; +import static com.android.systemui.accessibility.hearingaid.AmbientVolumeLayout.ROTATION_EXPANDED; +import static com.android.systemui.accessibility.hearingaid.AmbientVolumeLayout.SIDE_UNIFIED; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.util.ArrayMap; +import android.view.View; +import android.widget.ImageView; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.settingslib.bluetooth.AmbientVolumeUi; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Map; + +/** Tests for {@link AmbientVolumeLayout}. */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AmbientVolumeLayoutTest extends SysuiTestCase { + + private static final int TEST_LEFT_VOLUME_LEVEL = 1; + private static final int TEST_RIGHT_VOLUME_LEVEL = 2; + private static final int TEST_UNIFIED_VOLUME_LEVEL = 3; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private AmbientVolumeUi.AmbientVolumeUiListener mListener; + + private AmbientVolumeLayout mLayout; + private ImageView mExpandIcon; + private ImageView mVolumeIcon; + private final Map<Integer, BluetoothDevice> mSideToDeviceMap = new ArrayMap<>(); + + @Before + public void setUp() { + mLayout = new AmbientVolumeLayout(mContext); + mLayout.setListener(mListener); + mLayout.setExpandable(true); + mLayout.setMutable(true); + + prepareDevices(); + mLayout.setupSliders(mSideToDeviceMap); + mLayout.getSliders().forEach((side, slider) -> { + slider.setMin(0); + slider.setMax(4); + if (side == SIDE_LEFT) { + slider.setValue(TEST_LEFT_VOLUME_LEVEL); + } else if (side == SIDE_RIGHT) { + slider.setValue(TEST_RIGHT_VOLUME_LEVEL); + } else if (side == SIDE_UNIFIED) { + slider.setValue(TEST_UNIFIED_VOLUME_LEVEL); + } + }); + + mExpandIcon = mLayout.getExpandIcon(); + mVolumeIcon = mLayout.getVolumeIcon(); + } + + @Test + public void setExpandable_expandable_expandIconVisible() { + mLayout.setExpandable(true); + + assertThat(mExpandIcon.getVisibility()).isEqualTo(VISIBLE); + } + + @Test + public void setExpandable_notExpandable_expandIconGone() { + mLayout.setExpandable(false); + + assertThat(mExpandIcon.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void setExpanded_expanded_assertControlUiCorrect() { + mLayout.setExpanded(true); + + assertControlUiCorrect(); + } + + @Test + public void setExpanded_notExpanded_assertControlUiCorrect() { + mLayout.setExpanded(false); + + assertControlUiCorrect(); + } + + @Test + public void setMutable_mutable_clickOnMuteIconChangeMuteState() { + mLayout.setMutable(true); + mLayout.setMuted(false); + + mVolumeIcon.callOnClick(); + + assertThat(mLayout.isMuted()).isTrue(); + } + + @Test + public void setMutable_notMutable_clickOnMuteIconWontChangeMuteState() { + mLayout.setMutable(false); + mLayout.setMuted(false); + + mVolumeIcon.callOnClick(); + + assertThat(mLayout.isMuted()).isFalse(); + } + + @Test + public void updateLayout_mute_volumeIconIsCorrect() { + mLayout.setMuted(true); + mLayout.updateLayout(); + + assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(0); + } + + @Test + public void updateLayout_unmuteAndExpanded_volumeIconIsCorrect() { + mLayout.setMuted(false); + mLayout.setExpanded(true); + mLayout.updateLayout(); + + int expectedLevel = calculateVolumeLevel(TEST_LEFT_VOLUME_LEVEL, TEST_RIGHT_VOLUME_LEVEL); + assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel); + } + + @Test + public void updateLayout_unmuteAndNotExpanded_volumeIconIsCorrect() { + mLayout.setMuted(false); + mLayout.setExpanded(false); + mLayout.updateLayout(); + + int expectedLevel = calculateVolumeLevel(TEST_UNIFIED_VOLUME_LEVEL, + TEST_UNIFIED_VOLUME_LEVEL); + assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel); + } + + @Test + public void setSliderEnabled_expandedAndLeftIsDisabled_volumeIconIsCorrect() { + mLayout.setExpanded(true); + mLayout.setSliderEnabled(SIDE_LEFT, false); + + int expectedLevel = calculateVolumeLevel(0, TEST_RIGHT_VOLUME_LEVEL); + assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel); + } + + @Test + public void setSliderValue_expandedAndLeftValueChanged_volumeIconIsCorrect() { + mLayout.setExpanded(true); + mLayout.setSliderValue(SIDE_LEFT, 4); + + int expectedLevel = calculateVolumeLevel(4, TEST_RIGHT_VOLUME_LEVEL); + assertThat(mVolumeIcon.getDrawable().getLevel()).isEqualTo(expectedLevel); + } + + private int calculateVolumeLevel(int left, int right) { + return left * 5 + right; + } + + private void assertControlUiCorrect() { + final boolean expanded = mLayout.isExpanded(); + final Map<Integer, AmbientVolumeSlider> sliders = mLayout.getSliders(); + if (expanded) { + assertThat(sliders.get(SIDE_UNIFIED).getVisibility()).isEqualTo(GONE); + assertThat(sliders.get(SIDE_LEFT).getVisibility()).isEqualTo(VISIBLE); + assertThat(sliders.get(SIDE_RIGHT).getVisibility()).isEqualTo(VISIBLE); + assertThat(mExpandIcon.getRotation()).isEqualTo(ROTATION_EXPANDED); + } else { + assertThat(sliders.get(SIDE_UNIFIED).getVisibility()).isEqualTo(VISIBLE); + assertThat(sliders.get(SIDE_LEFT).getVisibility()).isEqualTo(GONE); + assertThat(sliders.get(SIDE_RIGHT).getVisibility()).isEqualTo(GONE); + assertThat(mExpandIcon.getRotation()).isEqualTo(ROTATION_COLLAPSED); + } + } + + private void prepareDevices() { + mSideToDeviceMap.put(SIDE_LEFT, mock(BluetoothDevice.class)); + mSideToDeviceMap.put(SIDE_RIGHT, mock(BluetoothDevice.class)); + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSliderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSliderTest.java new file mode 100644 index 000000000000..78dfda88a526 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSliderTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.hearingaid; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Tests for {@link AmbientVolumeLayout}. */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AmbientVolumeSliderTest extends SysuiTestCase { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private Context mContext = ApplicationProvider.getApplicationContext(); + + private AmbientVolumeSlider mSlider; + + @Before + public void setUp() { + mSlider = new AmbientVolumeSlider(mContext); + } + + @Test + public void setTitle_titleCorrect() { + final String testTitle = "test"; + mSlider.setTitle(testTitle); + + assertThat(mSlider.getTitle()).isEqualTo(testTitle); + } + + @Test + public void getVolumeLevel_valueMin_volumeLevelIsZero() { + prepareSlider(/* min= */ 0, /* max= */ 100, /* value= */ 0); + + // The volume level is divided into 5 levels: + // Level 0 corresponds to the minimum volume value. The range between the minimum and + // maximum volume is divided into 4 equal intervals, represented by levels 1 to 4. + assertThat(mSlider.getVolumeLevel()).isEqualTo(0); + } + + @Test + public void getVolumeLevel_valueMax_volumeLevelIsFour() { + prepareSlider(/* min= */ 0, /* max= */ 100, /* value= */ 100); + + assertThat(mSlider.getVolumeLevel()).isEqualTo(4); + } + + @Test + public void getVolumeLevel_volumeLevelIsCorrect() { + prepareSlider(/* min= */ 0, /* max= */ 100, /* value= */ 73); + + assertThat(mSlider.getVolumeLevel()).isEqualTo(3); + } + + private void prepareSlider(float min, float max, float value) { + mSlider.setMin(min); + mSlider.setMax(max); + mSlider.setValue(value); + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java index ad12c61ab5d1..43d0d69c428f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java @@ -16,8 +16,11 @@ package com.android.systemui.accessibility.hearingaid; +import static android.bluetooth.BluetoothDevice.BOND_BONDED; import static android.bluetooth.BluetoothHapClient.PRESET_INDEX_UNAVAILABLE; +import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; import static com.android.systemui.accessibility.hearingaid.HearingDevicesDialogDelegate.LIVE_CAPTION_INTENT; import static com.google.common.truth.Truth.assertThat; @@ -31,6 +34,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.AudioInputControl; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHapPresetInfo; import android.bluetooth.BluetoothProfile; @@ -61,6 +65,7 @@ import com.android.settingslib.bluetooth.HapClientProfile; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.bluetooth.VolumeControlProfile; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogTransitionAnimator; @@ -90,6 +95,7 @@ import java.util.List; @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class HearingDevicesDialogDelegateTest extends SysuiTestCase { + @Rule public MockitoRule mockito = MockitoJUnit.rule(); @@ -120,6 +126,8 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { @Mock private HapClientProfile mHapClientProfile; @Mock + private VolumeControlProfile mVolumeControlProfile; + @Mock private CachedBluetoothDeviceManager mCachedDeviceManager; @Mock private BluetoothEventManager mBluetoothEventManager; @@ -151,21 +159,25 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter); when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager); when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); + when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile); when(mLocalBluetoothAdapter.isEnabled()).thenReturn(true); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(List.of(mCachedDevice)); when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager); when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); - when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice.getBondState()).thenReturn(BOND_BONDED); when(mDevice.isConnected()).thenReturn(true); when(mCachedDevice.getDevice()).thenReturn(mDevice); when(mCachedDevice.getAddress()).thenReturn(DEVICE_ADDRESS); when(mCachedDevice.getName()).thenReturn(DEVICE_NAME); - when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile)); + when(mCachedDevice.getProfiles()).thenReturn( + List.of(mHapClientProfile, mVolumeControlProfile)); when(mCachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true); when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true); when(mCachedDevice.isConnectedHapClientDevice()).thenReturn(true); when(mCachedDevice.getDrawableWithDescription()).thenReturn(new Pair<>(mDrawable, "")); + when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED); + when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT); when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice); mContext.setMockPackageManager(mPackageManager); @@ -292,6 +304,46 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { } @Test + @EnableFlags(com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_AMBIENT_VOLUME_CONTROL) + public void showDialog_deviceNotSupportVcp_ambientLayoutGone() { + when(mCachedDevice.getProfiles()).thenReturn(List.of()); + + setUpDeviceDialogWithoutPairNewDeviceButton(); + mDialog.show(); + + ViewGroup ambientLayout = getAmbientLayout(mDialog); + assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE); + } + + @Test + @EnableFlags(com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_AMBIENT_VOLUME_CONTROL) + public void showDialog_ambientControlNotAvailable_ambientLayoutGone() { + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn(List.of()); + + setUpDeviceDialogWithoutPairNewDeviceButton(); + mDialog.show(); + + ViewGroup ambientLayout = getAmbientLayout(mDialog); + assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE); + } + + @Test + @EnableFlags(com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_AMBIENT_VOLUME_CONTROL) + public void showDialog_supportVcpAndAmbientControlAvailable_ambientLayoutVisible() { + when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile)); + AudioInputControl audioInputControl = prepareAudioInputControl(); + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn( + List.of(audioInputControl)); + when(mVolumeControlProfile.getConnectionStatus(mDevice)).thenReturn(STATE_CONNECTED); + + setUpDeviceDialogWithoutPairNewDeviceButton(); + mDialog.show(); + + ViewGroup ambientLayout = getAmbientLayout(mDialog); + assertThat(ambientLayout.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test public void onActiveDeviceChanged_presetExist_presetSelected() { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); @@ -368,6 +420,10 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { return dialog.requireViewById(R.id.preset_layout); } + private ViewGroup getAmbientLayout(SystemUIDialog dialog) { + return dialog.requireViewById(R.id.ambient_layout); + } + private int countChildWithoutSpace(ViewGroup viewGroup) { int spaceCount = 0; @@ -388,6 +444,16 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { assertThat(toolsLayout.getVisibility()).isEqualTo(targetVisibility); } + private AudioInputControl prepareAudioInputControl() { + AudioInputControl audioInputControl = mock(AudioInputControl.class); + when(audioInputControl.getAudioInputType()).thenReturn( + AudioInputControl.AUDIO_INPUT_TYPE_AMBIENT); + when(audioInputControl.getGainMode()).thenReturn(AudioInputControl.GAIN_MODE_MANUAL); + when(audioInputControl.getAudioInputStatus()).thenReturn( + AudioInputControl.AUDIO_INPUT_STATUS_ACTIVE); + return audioInputControl; + } + @After public void reset() { if (mDialogDelegate != null) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt index fa5af510fec1..77e386963129 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.kt @@ -127,6 +127,7 @@ class ShadeTouchHandlerTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @DisableFlags( Flags.FLAG_COMMUNAL_HUB, + Flags.FLAG_GLANCEABLE_HUB_V2, Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX, Flags.FLAG_SCENE_CONTAINER, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt index 41cc6ee182cf..cbb6f81a015d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.back.domain.interactor +import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider @@ -31,6 +32,7 @@ import androidx.test.filters.SmallTest import com.android.internal.statusbar.IStatusBarService import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.CommunalBackActionInteractor import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope @@ -93,6 +95,7 @@ class BackActionInteractorTest : SysuiTestCase() { @Mock private lateinit var onBackInvokedDispatcher: WindowOnBackInvokedDispatcher @Mock private lateinit var iStatusBarService: IStatusBarService @Mock private lateinit var headsUpManager: HeadsUpManager + @Mock private lateinit var communalBackActionInteractor: CommunalBackActionInteractor private val keyguardRepository = FakeKeyguardRepository() private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor by lazy { @@ -117,6 +120,7 @@ class BackActionInteractorTest : SysuiTestCase() { windowRootViewVisibilityInteractor, shadeBackActionInteractor, qsController, + communalBackActionInteractor, ) } @@ -164,17 +168,6 @@ class BackActionInteractorTest : SysuiTestCase() { } @Test - fun testOnBackRequested_closeUserSwitcherIfOpen() { - whenever(shadeBackActionInteractor.closeUserSwitcherIfOpen()).thenReturn(true) - - val result = backActionInteractor.onBackRequested() - - assertTrue(result) - verify(statusBarKeyguardViewManager, never()).onBackPressed() - verify(shadeBackActionInteractor, never()).animateCollapseQs(anyBoolean()) - } - - @Test fun testOnBackRequested_returnsFalse() { // make shouldBackBeHandled return false whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) @@ -306,6 +299,19 @@ class BackActionInteractorTest : SysuiTestCase() { verify(shadeBackActionInteractor).onBackProgressed(0.4f) } + @Test + @EnableFlags(Flags.FLAG_GLANCEABLE_HUB_BACK_ACTION) + fun onBackAction_communalCanBeDismissed_communalBackActionInteractorCalled() { + backActionInteractor.start() + windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true) + powerInteractor.setAwakeForTest() + val callback = getBackInvokedCallback() + whenever(communalBackActionInteractor.canBeDismissed()).thenReturn(true) + callback.onBackInvoked() + + verify(communalBackActionInteractor).onBackPressed() + } + private fun getBackInvokedCallback(): OnBackInvokedCallback { testScope.runCurrent() val captor = argumentCaptor<OnBackInvokedCallback>() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/model b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt index 08f139c6a3af..9c9d5adcfcc9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/model +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt @@ -51,7 +51,7 @@ class BiometricPromptRequestTest : SysuiTestCase() { title = title, subtitle = subtitle, description = description, - contentView = contentView + contentView = contentView, ), BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID), @@ -101,9 +101,7 @@ class BiometricPromptRequestTest : SysuiTestCase() { val fpPros = fingerprintSensorPropertiesInternal().first() val request = BiometricPromptRequest.Biometric( - promptInfo( - logoBitmap = logoBitmap, - ), + promptInfo(logoBitmap = logoBitmap), BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID), BiometricModalities(fingerprintProperties = fpPros), @@ -162,7 +160,7 @@ class BiometricPromptRequestTest : SysuiTestCase() { BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID), stealth, - ) + ), ) for (request in toCheck) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalMetricsStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalMetricsStartableTest.kt index 370adee44a42..03bf79bc7a38 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalMetricsStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalMetricsStartableTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.communal import android.app.StatsManager import android.app.StatsManager.StatsPullAtomCallback import android.content.pm.UserInfo +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.util.StatsEvent import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -32,6 +33,7 @@ import com.android.systemui.communal.shared.log.CommunalMetricsLogger import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.settings.fakeUserTracker import com.android.systemui.shared.system.SysUiStatsLog @@ -75,10 +77,7 @@ class CommunalMetricsStartableTest : SysuiTestCase() { // Set up an existing user, which is required for widgets to show val userInfos = listOf(UserInfo(0, "main", UserInfo.FLAG_MAIN)) userRepository.setUserInfos(userInfos) - userTracker.set( - userInfos = userInfos, - selectedUserIndex = 0, - ) + userTracker.set(userInfos = userInfos, selectedUserIndex = 0) underTest = CommunalMetricsStartable( @@ -90,14 +89,16 @@ class CommunalMetricsStartableTest : SysuiTestCase() { ) } + @DisableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) @Test - fun start_communalFlagDisabled_doNotSetPullAtomCallback() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) + fun start_communalFlagDisabled_doNotSetPullAtomCallback() = + kosmos.runTest { + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) - underTest.start() + underTest.start() - verify(statsManager, never()).setPullAtomCallback(anyInt(), anyOrNull(), any(), any()) - } + verify(statsManager, never()).setPullAtomCallback(anyInt(), anyOrNull(), any(), any()) + } @Test fun onPullAtom_atomTagDoesNotMatch_pullSkip() { 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 b66727e492cf..038ea9ccaaa9 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 @@ -26,8 +26,8 @@ import android.content.res.mainResources import android.os.UserManager.USER_TYPE_PROFILE_MANAGED import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 @@ -35,10 +35,13 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher 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.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.nullable @@ -51,15 +54,21 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.eq +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalSettingsRepositoryImplTest : SysuiTestCase() { +@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 + init { + mSetFlagsRule.setFlagsParameterization(flags!!) + } + @Before fun setUp() { kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) @@ -164,17 +173,17 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_INVALID_USER) } - @EnableFlags(FLAG_COMMUNAL_HUB) + @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) @Test fun classicFlagIsDisabled() = - testScope.runTest { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) + kosmos.runTest { + setCommunalV2Enabled(false) val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledState?.enabled).isFalse() assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) } - @DisableFlags(FLAG_COMMUNAL_HUB) + @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) @Test fun communalHubFlagIsDisabled() = testScope.runTest { @@ -295,6 +304,34 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { } } + @Test + fun screensaverDisabledByUser() = + testScope.runTest { + val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) + + kosmos.fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ENABLED, + 0, + PRIMARY_USER.id, + ) + + assertThat(enabledState).isFalse() + } + + @Test + fun screensaverEnabledByUser() = + testScope.runTest { + val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) + + kosmos.fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ENABLED, + 1, + PRIMARY_USER.id, + ) + + assertThat(enabledState).isTrue() + } + private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) @@ -310,5 +347,11 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { val SECONDARY_USER = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) val WORK_PROFILE = UserInfo(10, "work", /* iconPath= */ "", /* flags= */ 0, USER_TYPE_PROFILE_MANAGED) + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2) + } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt new file mode 100644 index 000000000000..c365f1cb3872 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorTest.kt @@ -0,0 +1,63 @@ +/* + * 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.communal.domain.interactor + +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_COMMUNAL_HUB +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.communalSceneRepository +import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +class CommunalBackActionInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + + private var Kosmos.underTest by Fixture { communalBackActionInteractor } + + @Test + @EnableFlags(FLAG_COMMUNAL_HUB) + fun communalShowing_canBeDismissed() = + kosmos.runTest { + setCommunalAvailable(true) + assertThat(underTest.canBeDismissed()).isEqualTo(false) + communalInteractor.changeScene(CommunalScenes.Communal, "test") + runCurrent() + assertThat(underTest.canBeDismissed()).isEqualTo(true) + } + + @Test + @EnableFlags(FLAG_COMMUNAL_HUB) + fun onBackPressed_invokesSceneChange() = + kosmos.runTest { + underTest.onBackPressed() + runCurrent() + assertThat(communalSceneRepository.currentScene.value).isEqualTo(CommunalScenes.Blank) + } +} 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 b9e646fee98f..7ae0577bd289 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 @@ -35,6 +35,7 @@ import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_COMMUNAL_RESPONSIVE_GRID 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.communal.data.model.CommunalSmartspaceTimer @@ -232,7 +233,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun isCommunalAvailable_communalDisabled_false() = testScope.runTest { - mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB) + mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt index 0bfcd242828d..8a9c42d9b64e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt @@ -130,19 +130,6 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { } @Test - fun tutorialState_startedAndCommunalSceneShowing_stateWillNotUpdate() = - testScope.runTest { - val tutorialSettingState by - collectLastValue(communalTutorialRepository.tutorialSettingState) - - communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED) - - goToCommunal() - - assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED) - } - - @Test fun tutorialState_completedAndCommunalSceneShowing_stateWillNotUpdate() = testScope.runTest { val tutorialSettingState by diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModelTest.kt index a8a3873d6de2..92719807bf10 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.communal.widgets.CommunalAppWidgetHost import com.android.systemui.communal.widgets.GlanceableHubWidgetManager import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.backgroundCoroutineContext import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest @@ -57,8 +58,8 @@ class CommunalAppWidgetViewModelTest(flags: FlagsParameterization) : SysuiTestCa private val Kosmos.listenerDelegateFactory by Kosmos.Fixture { - AppWidgetHostListenerDelegate.Factory { listener -> - AppWidgetHostListenerDelegate(fakeExecutor, listener) + AppWidgetHostListenerDelegate.Factory { tag, listener -> + AppWidgetHostListenerDelegate(applicationCoroutineScope, tag, listener) } } 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 88206850eb60..b78080885b0a 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 @@ -17,6 +17,7 @@ package com.android.systemui.communal.ui.viewmodel import android.platform.test.annotations.EnableFlags +import android.provider.Settings import android.service.dream.dreamManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -29,12 +30,16 @@ 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.statusbar.policy.batteryController import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.whenever @@ -56,10 +61,9 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { } @Test - fun shouldShowDreamButtonOnHub_trueWhenCanDream() = + fun shouldShowDreamButtonOnHub_trueWhenPluggedIn() = with(kosmos) { runTest { - whenever(dreamManager.canStartDreaming(any())).thenReturn(true) whenever(batteryController.isPluggedIn()).thenReturn(true) val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) @@ -68,11 +72,10 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { } @Test - fun shouldShowDreamButtonOnHub_falseWhenCannotDream() = + fun shouldShowDreamButtonOnHub_falseWhenNotPluggedIn() = with(kosmos) { runTest { - whenever(dreamManager.canStartDreaming(any())).thenReturn(false) - whenever(batteryController.isPluggedIn()).thenReturn(true) + whenever(batteryController.isPluggedIn()).thenReturn(false) val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) assertThat(shouldShowButton).isFalse() @@ -80,25 +83,40 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { } @Test - fun shouldShowDreamButtonOnHub_falseWhenNotPluggedIn() = + fun onShowDreamButtonTap_dreamsEnabled_startsDream() = with(kosmos) { runTest { - whenever(dreamManager.canStartDreaming(any())).thenReturn(true) - whenever(batteryController.isPluggedIn()).thenReturn(false) + val currentUser = fakeUserRepository.asMainUser() + kosmos.fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ENABLED, + 1, + currentUser.id, + ) + runCurrent() - val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) - assertThat(shouldShowButton).isFalse() + underTest.onShowDreamButtonTap() + runCurrent() + + verify(dreamManager).startDream() } } @Test - fun onShowDreamButtonTap_startsDream() = + fun onShowDreamButtonTap_dreamsDisabled_startsActivity() = with(kosmos) { runTest { + val currentUser = fakeUserRepository.asMainUser() + kosmos.fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ENABLED, + 0, + currentUser.id, + ) + runCurrent() + underTest.onShowDreamButtonTap() runCurrent() - verify(dreamManager).startDream() + verify(activityStarter).postStartActivityDismissingKeyguard(any(), anyInt()) } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt index 017c77828cdc..214cd1af9b30 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt @@ -27,10 +27,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.applicationCoroutineScope -import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.log.logcatLogBuffer import com.android.systemui.testKosmos import com.android.systemui.user.data.model.SelectedUserModel @@ -43,10 +44,6 @@ import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import java.util.Optional -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -58,11 +55,9 @@ import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) class CommunalWidgetHostTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope + private val kosmos = testKosmos().useUnconfinedTestDispatcher() @Mock private lateinit var appWidgetManager: AppWidgetManager @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost @@ -103,12 +98,11 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun allocateIdAndBindWidget_withCurrentUser() = - testScope.runTest { + kosmos.runTest { val provider = ComponentName("pkg_name", "cls_name") val widgetId = 1 val userId by collectLastValue(selectedUserInteractor.selectedUser) selectUser() - runCurrent() val user = UserHandle(checkNotNull(userId)) whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(widgetId) @@ -129,7 +123,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun allocateIdAndBindWidget_onSuccess() = - testScope.runTest { + kosmos.runTest { val provider = ComponentName("pkg_name", "cls_name") val widgetId = 1 val user = UserHandle(0) @@ -152,7 +146,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun allocateIdAndBindWidget_onFailure() = - testScope.runTest { + kosmos.runTest { val provider = ComponentName("pkg_name", "cls_name") val widgetId = 1 val user = UserHandle(0) @@ -179,12 +173,11 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun listener_exactlyOneListenerRegisteredForEachWidgetWhenHostStartListening() = - testScope.runTest { + kosmos.runTest { // 3 widgets registered with the host whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2, 3)) underTest.startObservingHost() - runCurrent() // Make sure no listener is set before host starts listening verify(appWidgetHost, never()).setListener(any(), any()) @@ -195,7 +188,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { verify(appWidgetHost).addObserver(capture()) } observer.onHostStartListening() - runCurrent() // Verify a listener is set for each widget verify(appWidgetHost, times(3)).setListener(any(), any()) @@ -206,12 +198,11 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun listener_listenersRemovedWhenHostStopListening() = - testScope.runTest { + kosmos.runTest { // 3 widgets registered with the host whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2, 3)) underTest.startObservingHost() - runCurrent() // Host starts listening val observer = @@ -219,7 +210,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { verify(appWidgetHost).addObserver(capture()) } observer.onHostStartListening() - runCurrent() // Verify none of the listener is removed before host stop listening verify(appWidgetHost, never()).removeListener(any()) @@ -235,7 +225,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun listener_addNewListenerWhenNewIdAllocated() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf()) val observer = start() @@ -251,7 +241,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun listener_removeListenerWhenWidgetDeleted() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1)) val observer = start() @@ -267,7 +257,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun providerInfo_populatesWhenStartListening() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2)) whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1) whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2) @@ -279,7 +269,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { assertThat(providerInfoValues[0]).isEmpty() start() - runCurrent() // Assert that the provider info map is populated after host started listening, and that // all providers are emitted at once @@ -290,13 +279,12 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun providerInfo_clearsWhenStopListening() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2)) whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1) whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2) val observer = start() - runCurrent() // Assert that the provider info map is populated val providerInfo by collectLastValue(underTest.appWidgetProviders) @@ -312,7 +300,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun providerInfo_onUpdate() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2)) whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1) whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2) @@ -320,7 +308,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { val providerInfo by collectLastValue(underTest.appWidgetProviders) start() - runCurrent() // Assert that the provider info map is populated assertThat(providerInfo) @@ -332,7 +319,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { verify(appWidgetHost).setListener(eq(1), capture()) } listener.onUpdateProviderInfo(providerInfo3) - runCurrent() // Assert that the update is reflected in the flow assertThat(providerInfo) @@ -341,7 +327,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun providerInfo_updateWhenANewWidgetIsBound() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2)) whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1) whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2) @@ -349,7 +335,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { val providerInfo by collectLastValue(underTest.appWidgetProviders) start() - runCurrent() // Assert that the provider info map is populated assertThat(providerInfo) @@ -360,7 +345,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { whenever(appWidgetManager.getAppWidgetInfo(3)).thenReturn(providerInfo3) val newWidgetComponentName = ComponentName.unflattenFromString("pkg_new/cls_new")!! underTest.allocateIdAndBindWidget(newWidgetComponentName) - runCurrent() // Assert that the new provider is reflected in the flow assertThat(providerInfo) @@ -371,7 +355,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { @Test fun providerInfo_updateWhenWidgetRemoved() = - testScope.runTest { + kosmos.runTest { whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2)) whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1) whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2) @@ -379,7 +363,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { val providerInfo by collectLastValue(underTest.appWidgetProviders) val observer = start() - runCurrent() // Assert that the provider info map is populated assertThat(providerInfo) @@ -387,7 +370,6 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Remove widget 1 observer.onDeleteAppWidgetId(1) - runCurrent() // Assert that provider info for widget 1 is removed assertThat(providerInfo).containsExactlyEntriesIn(mapOf(Pair(2, providerInfo2))) @@ -401,9 +383,8 @@ class CommunalWidgetHostTest : SysuiTestCase() { ) } - private fun TestScope.start(): CommunalAppWidgetHost.Observer { + private fun start(): CommunalAppWidgetHost.Observer { underTest.startObservingHost() - runCurrent() val observer = withArgCaptor<CommunalAppWidgetHost.Observer> { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/ControlActionCoordinatorImplTest.kt index 928514657257..c8661cf59051 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/ControlActionCoordinatorImplTest.kt @@ -16,9 +16,9 @@ package com.android.systemui.controls.ui +import android.view.HapticFeedbackConstants import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import android.view.HapticFeedbackConstants import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.controls.ControlsMetricsLogger @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.wm.shell.taskview.TaskViewFactory +import java.util.Optional import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -45,31 +46,20 @@ import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations -import java.util.Optional @SmallTest @RunWith(AndroidJUnit4::class) class ControlActionCoordinatorImplTest : SysuiTestCase() { - @Mock - private lateinit var vibratorHelper: VibratorHelper - @Mock - private lateinit var keyguardStateController: KeyguardStateController - @Mock - private lateinit var bgExecutor: DelayableExecutor - @Mock - private lateinit var uiExecutor: DelayableExecutor - @Mock - private lateinit var activityStarter: ActivityStarter - @Mock - private lateinit var broadcastSender: BroadcastSender - @Mock - private lateinit var taskViewFactory: Optional<TaskViewFactory> - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private lateinit var cvh: ControlViewHolder - @Mock - private lateinit var metricsLogger: ControlsMetricsLogger - @Mock - private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager + @Mock private lateinit var vibratorHelper: VibratorHelper + @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var bgExecutor: DelayableExecutor + @Mock private lateinit var uiExecutor: DelayableExecutor + @Mock private lateinit var activityStarter: ActivityStarter + @Mock private lateinit var broadcastSender: BroadcastSender + @Mock private lateinit var taskViewFactory: Optional<TaskViewFactory> + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var cvh: ControlViewHolder + @Mock private lateinit var metricsLogger: ControlsMetricsLogger + @Mock private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager companion object { fun <T> any(): T = Mockito.any<T>() @@ -89,18 +79,21 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true) controlsSettingsRepository.setCanShowControlsInLockscreen(true) - coordinator = spy(ControlActionCoordinatorImpl( - mContext, - bgExecutor, - uiExecutor, - activityStarter, - broadcastSender, - keyguardStateController, - taskViewFactory, - metricsLogger, - vibratorHelper, - controlsSettingsRepository, - )) + coordinator = + spy( + ControlActionCoordinatorImpl( + mContext, + bgExecutor, + uiExecutor, + activityStarter, + broadcastSender, + keyguardStateController, + taskViewFactory, + metricsLogger, + vibratorHelper, + controlsSettingsRepository, + ) + ) coordinator.activityContext = mContext `when`(cvh.cws.ci.controlId).thenReturn(ID) @@ -198,19 +191,15 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() { fun drag_isEdge_performsSegmentTickHaptics() { coordinator.drag(cvh, true) - verify(vibratorHelper).performHapticFeedback( - any(), - eq(HapticFeedbackConstants.SEGMENT_TICK) - ) + verify(vibratorHelper) + .performHapticFeedback(any(), eq(HapticFeedbackConstants.SEGMENT_TICK)) } @Test fun drag_isNotEdge_performsFrequentTickHaptics() { coordinator.drag(cvh, false) - verify(vibratorHelper).performHapticFeedback( - any(), - eq(HapticFeedbackConstants.SEGMENT_FREQUENT_TICK) - ) + verify(vibratorHelper) + .performHapticFeedback(any(), eq(HapticFeedbackConstants.SEGMENT_FREQUENT_TICK)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt index b07097d61b96..5921e9479bd9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt @@ -92,10 +92,10 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mockito import org.mockito.Mockito.clearInvocations -import org.mockito.Mockito.isNull import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.firstValue @@ -768,7 +768,7 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() { runCurrent() verify(mDreamOverlayCallback).onRedirectWake(true) client.onWakeRequested() - verify(mCommunalInteractor).changeScene(eq(CommunalScenes.Communal), any(), isNull()) + verify(mCommunalInteractor).changeScene(eq(CommunalScenes.Communal), any(), anyOrNull()) verify(mUiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/system/domain/interactor/HomeControlsComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt index c950523f7854..c950523f7854 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/system/domain/interactor/HomeControlsComponentInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt index 9cfd328a9484..f2a6c11b872e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -43,6 +44,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) +@Ignore("b/384284415") class ContextualEducationRepositoryTest : SysuiTestCase() { private lateinit var underTest: UserContextualEducationRepository diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt index ee3e241b5754..56e8185ab580 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt @@ -81,7 +81,7 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() { // Then verify(cameraGestureHelper) .launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE) - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true), result) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt index 50ac26196978..fde9b8ce6a50 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt @@ -197,7 +197,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { val dndMode = currentModes!!.single() assertThat(dndMode.isActive).isFalse() - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) } @Test @@ -222,7 +222,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { ) // then - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) assertEquals(ZEN_MODE_OFF, spyZenMode.value) assertNull(spyConditionId.value) } @@ -244,7 +244,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { val dndMode = currentModes!!.single() assertThat(dndMode.isActive).isTrue() assertThat(zenModeRepository.getModeActiveDuration(dndMode.id)).isNull() - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) } @Test @@ -268,7 +268,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { ) // then - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, spyZenMode.value) assertNull(spyConditionId.value) } @@ -285,7 +285,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { val result = underTest.onTriggered(null) runCurrent() - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) val dndMode = currentModes!!.single() assertThat(dndMode.isActive).isTrue() assertThat(zenModeRepository.getModeActiveDuration(dndMode.id)) @@ -313,7 +313,7 @@ class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { ) // then - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, spyZenMode.value) assertEquals(conditionUri, spyConditionId.value) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt index 789b10b7830c..ac06a3b9293c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt @@ -24,21 +24,19 @@ import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.communalSceneRepository -import com.android.systemui.communal.domain.interactor.communalInteractor -import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.communal.domain.interactor.setCommunalV2Available import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalScenes -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.andSceneContainer -import com.android.systemui.kosmos.testScope +import com.android.systemui.flags.parameterizeSceneContainerFlag +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest import com.android.systemui.scene.data.repository.sceneContainerRepository -import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -47,14 +45,11 @@ import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters @SmallTest -@OptIn(ExperimentalCoroutinesApi::class) -@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON, Flags.FLAG_GLANCEABLE_HUB_V2) +@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) @RunWith(ParameterizedAndroidJunit4::class) class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : SysuiTestCase() { private val kosmos = testKosmos() - private val testScope = kosmos.testScope - - private lateinit var underTest: GlanceableHubQuickAffordanceConfig + private val Kosmos.underTest by Kosmos.Fixture { glanceableHubQuickAffordanceConfig } init { mSetFlagsRule.setFlagsParameterization(flags!!) @@ -64,20 +59,16 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy fun setUp() { MockitoAnnotations.initMocks(this) - underTest = - GlanceableHubQuickAffordanceConfig( - context = context, - communalInteractor = kosmos.communalInteractor, - communalSceneRepository = kosmos.communalSceneRepository, - communalSettingsInteractor = kosmos.communalSettingsInteractor, - sceneInteractor = kosmos.sceneInteractor, - ) + // Access the class immediately so that flows are instantiated. + // GlanceableHubQuickAffordanceConfig accesses StateFlow.value directly so we need the flows + // to start flowing before runCurrent is called in the tests. + kosmos.underTest } @Test fun lockscreenState_whenGlanceableHubEnabled_returnsVisible() = - testScope.runTest { - kosmos.setCommunalV2Enabled(true) + kosmos.runTest { + kosmos.setCommunalV2Available(true) runCurrent() val lockScreenState by collectLastValue(underTest.lockScreenState) @@ -88,8 +79,21 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test fun lockscreenState_whenGlanceableHubDisabled_returnsHidden() = - testScope.runTest { - kosmos.setCommunalV2Enabled(false) + kosmos.runTest { + setCommunalV2Enabled(false) + val lockScreenState by collectLastValue(underTest.lockScreenState) + runCurrent() + + assertThat(lockScreenState) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } + + @Test + fun lockscreenState_whenGlanceableHubNotAvailable_returnsHidden() = + kosmos.runTest { + // Hub is enabled, but not available. + setCommunalV2Enabled(true) + fakeKeyguardRepository.setKeyguardShowing(false) val lockScreenState by collectLastValue(underTest.lockScreenState) runCurrent() @@ -99,8 +103,8 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test fun pickerScreenState_whenGlanceableHubEnabled_returnsDefault() = - testScope.runTest { - kosmos.setCommunalV2Enabled(true) + kosmos.runTest { + setCommunalV2Enabled(true) runCurrent() assertThat(underTest.getPickerScreenState()) @@ -109,8 +113,8 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test fun pickerScreenState_whenGlanceableHubDisabled_returnsDisabled() = - testScope.runTest { - kosmos.setCommunalV2Enabled(false) + kosmos.runTest { + setCommunalV2Enabled(false) runCurrent() assertThat( @@ -122,7 +126,7 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test @DisableFlags(Flags.FLAG_SCENE_CONTAINER) fun onTriggered_changesSceneToCommunal() = - testScope.runTest { + kosmos.runTest { underTest.onTriggered(expandable = null) runCurrent() @@ -133,7 +137,7 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test @EnableFlags(Flags.FLAG_SCENE_CONTAINER) fun testTransitionToGlanceableHub_sceneContainer() = - testScope.runTest { + kosmos.runTest { underTest.onTriggered(expandable = null) runCurrent() @@ -145,11 +149,7 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @JvmStatic @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { - return FlagsParameterization.allCombinationsOf( - Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON, - Flags.FLAG_GLANCEABLE_HUB_V2, - ) - .andSceneContainer() + return parameterizeSceneContainerFlag() } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceHapticViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceHapticViewModelTest.kt new file mode 100644 index 000000000000..18946f9d7e07 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceHapticViewModelTest.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.data.quickaffordance + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.domain.interactor.keyguardQuickAffordanceHapticViewModelFactory +import com.android.systemui.keyguard.domain.interactor.keyguardQuickAffordanceInteractor +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceHapticViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel +import com.android.systemui.kosmos.testScope +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +class KeyguardQuickAffordanceHapticViewModelTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + private val configKey = "$slotId::home" + private val keyguardQuickAffordanceInteractor = kosmos.keyguardQuickAffordanceInteractor + private val viewModelFlow = + MutableStateFlow(KeyguardQuickAffordanceViewModel(configKey = configKey, slotId = slotId)) + + private val underTest = + kosmos.keyguardQuickAffordanceHapticViewModelFactory.create(viewModelFlow) + + @Test + fun whenLaunchingFromTriggeredResult_hapticStateIsLaunch() = + testScope.runTest { + // GIVEN that the result from triggering the affordance launched an activity or dialog + val hapticState by collectLastValue(underTest.quickAffordanceHapticState) + keyguardQuickAffordanceInteractor.setLaunchingFromTriggeredResult( + KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult(true, configKey) + ) + runCurrent() + + // THEN the haptic state indicates that a launch haptics must play + assertThat(hapticState) + .isEqualTo(KeyguardQuickAffordanceHapticViewModel.HapticState.LAUNCH) + } + + @Test + fun whenNotLaunchFromTriggeredResult_hapticStateDoesNotEmit() = + testScope.runTest { + // GIVEN that the result from triggering the affordance did not launch an activity or + // dialog + val hapticState by collectLastValue(underTest.quickAffordanceHapticState) + keyguardQuickAffordanceInteractor.setLaunchingFromTriggeredResult( + KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult(false, configKey) + ) + runCurrent() + + // THEN there is no haptic state to play any feedback + assertThat(hapticState) + .isEqualTo(KeyguardQuickAffordanceHapticViewModel.HapticState.NO_HAPTICS) + } + + @Test + fun onQuickAffordanceTogglesToActivated_hapticStateIsToggleOn() = + testScope.runTest { + // GIVEN that an affordance toggles from deactivated to activated + val hapticState by collectLastValue(underTest.quickAffordanceHapticState) + toggleQuickAffordance(on = true) + + // THEN the haptic state reflects that a toggle on haptics should play + assertThat(hapticState) + .isEqualTo(KeyguardQuickAffordanceHapticViewModel.HapticState.TOGGLE_ON) + } + + @Test + fun onQuickAffordanceTogglesToDeactivated_hapticStateIsToggleOff() = + testScope.runTest { + // GIVEN that an affordance toggles from activated to deactivated + val hapticState by collectLastValue(underTest.quickAffordanceHapticState) + toggleQuickAffordance(on = false) + + // THEN the haptic state reflects that a toggle off haptics should play + assertThat(hapticState) + .isEqualTo(KeyguardQuickAffordanceHapticViewModel.HapticState.TOGGLE_OFF) + } + + private fun TestScope.toggleQuickAffordance(on: Boolean) { + underTest.updateActivatedHistory(!on) + runCurrent() + underTest.updateActivatedHistory(on) + runCurrent() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt index 4a422f05a45a..8c54ca1a629d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt @@ -23,6 +23,7 @@ import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher @@ -84,6 +85,7 @@ class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = FakeUserTracker(), + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) settings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 0) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt index 0f3e78b1fd7f..bc2c2d24fd2a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt @@ -20,13 +20,17 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Intent import android.content.SharedPreferences import android.content.pm.UserInfo +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.backup.BackupHelper +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.res.R import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserFileManager +import com.android.systemui.testKosmos import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat @@ -54,6 +58,7 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { + private val kosmos = testKosmos() @Mock private lateinit var userFileManager: UserFileManager @@ -80,6 +85,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { context = context, userFileManager = userFileManager, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) } @@ -110,27 +116,13 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { val affordanceId2 = "affordance2" val affordanceId3 = "affordance3" - underTest.setSelections( - slotId = slotId1, - affordanceIds = listOf(affordanceId1), - ) - assertSelections( - affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId1), - ), - ) + underTest.setSelections(slotId = slotId1, affordanceIds = listOf(affordanceId1)) + assertSelections(affordanceIdsBySlotId.last(), mapOf(slotId1 to listOf(affordanceId1))) - underTest.setSelections( - slotId = slotId2, - affordanceIds = listOf(affordanceId2), - ) + underTest.setSelections(slotId = slotId2, affordanceIds = listOf(affordanceId2)) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId1), - slotId2 to listOf(affordanceId2), - ) + mapOf(slotId1 to listOf(affordanceId1), slotId2 to listOf(affordanceId2)), ) underTest.setSelections( @@ -139,34 +131,19 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { ) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId1, affordanceId3), - slotId2 to listOf(affordanceId2), - ) + mapOf(slotId1 to listOf(affordanceId1, affordanceId3), slotId2 to listOf(affordanceId2)), ) - underTest.setSelections( - slotId = slotId1, - affordanceIds = listOf(affordanceId3), - ) + underTest.setSelections(slotId = slotId1, affordanceIds = listOf(affordanceId3)) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId3), - slotId2 to listOf(affordanceId2), - ) + mapOf(slotId1 to listOf(affordanceId3), slotId2 to listOf(affordanceId2)), ) - underTest.setSelections( - slotId = slotId2, - affordanceIds = listOf(), - ) + underTest.setSelections(slotId = slotId2, affordanceIds = listOf()) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId3), - slotId2 to listOf(), - ) + mapOf(slotId1 to listOf(affordanceId3), slotId2 to listOf()), ) job.cancel() @@ -174,10 +151,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { @Test fun remembersSelectionsByUser() = runTest { - overrideResource( - R.array.config_keyguardQuickAffordanceDefaults, - arrayOf<String>(), - ) + overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>()) val slot1 = "slot_1" val slot2 = "slot_2" val affordance1 = "affordance_1" @@ -195,60 +169,28 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { UserInfo(/* id= */ 0, "zero", /* flags= */ 0), UserInfo(/* id= */ 1, "one", /* flags= */ 0), ) - userTracker.set( - userInfos = userInfos, - selectedUserIndex = 0, - ) - underTest.setSelections( - slotId = slot1, - affordanceIds = listOf(affordance1), - ) - underTest.setSelections( - slotId = slot2, - affordanceIds = listOf(affordance2), - ) + userTracker.set(userInfos = userInfos, selectedUserIndex = 0) + underTest.setSelections(slotId = slot1, affordanceIds = listOf(affordance1)) + underTest.setSelections(slotId = slot2, affordanceIds = listOf(affordance2)) // Switch to user 1 - userTracker.set( - userInfos = userInfos, - selectedUserIndex = 1, - ) + userTracker.set(userInfos = userInfos, selectedUserIndex = 1) // We never set selections on user 1, so it should be empty. - assertSelections( - observed = affordanceIdsBySlotId.last(), - expected = emptyMap(), - ) + assertSelections(observed = affordanceIdsBySlotId.last(), expected = emptyMap()) // Now, let's set selections on user 1. - underTest.setSelections( - slotId = slot1, - affordanceIds = listOf(affordance2), - ) - underTest.setSelections( - slotId = slot2, - affordanceIds = listOf(affordance3), - ) + underTest.setSelections(slotId = slot1, affordanceIds = listOf(affordance2)) + underTest.setSelections(slotId = slot2, affordanceIds = listOf(affordance3)) assertSelections( observed = affordanceIdsBySlotId.last(), - expected = - mapOf( - slot1 to listOf(affordance2), - slot2 to listOf(affordance3), - ), + expected = mapOf(slot1 to listOf(affordance2), slot2 to listOf(affordance3)), ) // Switch back to user 0. - userTracker.set( - userInfos = userInfos, - selectedUserIndex = 0, - ) + userTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Assert that we still remember the old selections for user 0. assertSelections( observed = affordanceIdsBySlotId.last(), - expected = - mapOf( - slot1 to listOf(affordance1), - slot2 to listOf(affordance2), - ), + expected = mapOf(slot1 to listOf(affordance1), slot2 to listOf(affordance2)), ) job.cancel() @@ -276,10 +218,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId1, affordanceId3), - slotId2 to listOf(affordanceId2), - ), + mapOf(slotId1 to listOf(affordanceId1, affordanceId3), slotId2 to listOf(affordanceId2)), ) job.cancel() @@ -308,10 +247,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { underTest.setSelections(slotId1, listOf(affordanceId2)) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(affordanceId2), - slotId2 to listOf(affordanceId2), - ), + mapOf(slotId1 to listOf(affordanceId2), slotId2 to listOf(affordanceId2)), ) job.cancel() @@ -340,10 +276,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { underTest.setSelections(slotId1, listOf()) assertSelections( affordanceIdsBySlotId.last(), - mapOf( - slotId1 to listOf(), - slotId2 to listOf(affordanceId2), - ), + mapOf(slotId1 to listOf(), slotId2 to listOf(affordanceId2)), ) job.cancel() @@ -373,18 +306,36 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, false) overrideResource( R.array.config_keyguardQuickAffordanceDefaults, - arrayOf("leftTest:testShortcut1", "rightTest:testShortcut2") + arrayOf("leftTest:testShortcut1", "rightTest:testShortcut2"), ) assertThat(underTest.getSelections()) .isEqualTo( - mapOf( - "leftTest" to listOf("testShortcut1"), - "rightTest" to listOf("testShortcut2"), - ) + mapOf("leftTest" to listOf("testShortcut1"), "rightTest" to listOf("testShortcut2")) ) } + @EnableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) + @Test + fun getSelections_returnsSelectionsIfHubV2Enabled() = runTest { + overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, false) + overrideResource(com.android.internal.R.bool.config_glanceableHubEnabled, true) + + overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>()) + val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>() + val job = + launch(UnconfinedTestDispatcher()) { + underTest.selections.toList(affordanceIdsBySlotId) + } + val slotId1 = "slot1" + val affordanceId1 = "affordance1" + + underTest.setSelections(slotId = slotId1, affordanceIds = listOf(affordanceId1)) + assertSelections(affordanceIdsBySlotId.last(), mapOf(slotId1 to listOf(affordanceId1))) + + job.cancel() + } + private fun assertSelections( observed: Map<String, List<String>>?, expected: Map<String, List<String>>, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt index b15352bfe6ab..173b4e56075c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt @@ -49,14 +49,10 @@ import org.mockito.MockitoAnnotations class MuteQuickAffordanceConfigTest : SysuiTestCase() { private lateinit var underTest: MuteQuickAffordanceConfig - @Mock - private lateinit var ringerModeTracker: RingerModeTracker - @Mock - private lateinit var audioManager: AudioManager - @Mock - private lateinit var userTracker: UserTracker - @Mock - private lateinit var userFileManager: UserFileManager + @Mock private lateinit var ringerModeTracker: RingerModeTracker + @Mock private lateinit var audioManager: AudioManager + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var userFileManager: UserFileManager private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope @@ -70,9 +66,12 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() { whenever(userTracker.userContext).thenReturn(context) whenever(userFileManager.getSharedPreferences(any(), any(), any())) - .thenReturn(context.getSharedPreferences("mutequickaffordancetest", Context.MODE_PRIVATE)) + .thenReturn( + context.getSharedPreferences("mutequickaffordancetest", Context.MODE_PRIVATE) + ) - underTest = MuteQuickAffordanceConfig( + underTest = + MuteQuickAffordanceConfig( context, userTracker, userFileManager, @@ -81,64 +80,71 @@ class MuteQuickAffordanceConfigTest : SysuiTestCase() { testScope.backgroundScope, testDispatcher, testDispatcher, - ) + ) } @Test - fun pickerState_volumeFixed_notAvailable() = testScope.runTest { - //given - whenever(audioManager.isVolumeFixed).thenReturn(true) + fun pickerState_volumeFixed_notAvailable() = + testScope.runTest { + // given + whenever(audioManager.isVolumeFixed).thenReturn(true) - //when - val result = underTest.getPickerScreenState() + // when + val result = underTest.getPickerScreenState() - //then - assertEquals(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice, result) - } + // then + assertEquals( + KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice, + result, + ) + } @Test - fun pickerState_volumeNotFixed_available() = testScope.runTest { - //given - whenever(audioManager.isVolumeFixed).thenReturn(false) + fun pickerState_volumeNotFixed_available() = + testScope.runTest { + // given + whenever(audioManager.isVolumeFixed).thenReturn(false) - //when - val result = underTest.getPickerScreenState() + // when + val result = underTest.getPickerScreenState() - //then - assertEquals(KeyguardQuickAffordanceConfig.PickerScreenState.Default(), result) - } + // then + assertEquals(KeyguardQuickAffordanceConfig.PickerScreenState.Default(), result) + } @Test - fun triggered_stateWasPreviouslyNORMAL_currentlySILENT_moveToPreviousState() = testScope.runTest { - //given - val ringerModeCapture = argumentCaptor<Int>() - whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL) - underTest.onTriggered(null) - whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_SILENT) - - //when - val result = underTest.onTriggered(null) - runCurrent() - verify(audioManager, times(2)).ringerModeInternal = ringerModeCapture.capture() - - //then - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) - assertEquals(AudioManager.RINGER_MODE_NORMAL, ringerModeCapture.value) - } + fun triggered_stateWasPreviouslyNORMAL_currentlySILENT_moveToPreviousState() = + testScope.runTest { + // given + val ringerModeCapture = argumentCaptor<Int>() + whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL) + underTest.onTriggered(null) + whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_SILENT) + + // when + val result = underTest.onTriggered(null) + runCurrent() + verify(audioManager, times(2)).ringerModeInternal = ringerModeCapture.capture() + + // then + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) + assertEquals(AudioManager.RINGER_MODE_NORMAL, ringerModeCapture.value) + } @Test - fun triggered_stateIsNotSILENT_moveToSILENTringer() = testScope.runTest { - //given - val ringerModeCapture = argumentCaptor<Int>() - whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL) - - //when - val result = underTest.onTriggered(null) - runCurrent() - verify(audioManager).ringerModeInternal = ringerModeCapture.capture() - - //then - assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result) - assertEquals(AudioManager.RINGER_MODE_SILENT, ringerModeCapture.value) - } -}
\ No newline at end of file + fun triggered_stateIsNotSILENT_moveToSILENTringer() = + testScope.runTest { + // given + val ringerModeCapture = argumentCaptor<Int>() + whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL) + + // when + val result = underTest.onTriggered(null) + runCurrent() + verify(audioManager).ringerModeInternal = ringerModeCapture.capture() + + // then + assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false), result) + assertEquals(AudioManager.RINGER_MODE_SILENT, ringerModeCapture.value) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index e9b36b8b3b57..9bdc363b3a38 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -88,9 +88,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { Icon.Loaded( drawable = ICON, contentDescription = - ContentDescription.Resource( - res = R.string.accessibility_wallet_button, - ), + ContentDescription.Resource(res = R.string.accessibility_wallet_button), ) ) } @@ -118,9 +116,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { Icon.Loaded( drawable = ICON, contentDescription = - ContentDescription.Resource( - res = R.string.accessibility_wallet_button, - ), + ContentDescription.Resource(res = R.string.accessibility_wallet_button), ) ) } @@ -163,13 +159,9 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } assertThat(underTest.onTriggered(expandable)) - .isEqualTo(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled) + .isEqualTo(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true)) verify(walletController) - .startQuickAccessUiIntent( - activityStarter, - animationController, - /* hasCard= */ true, - ) + .startQuickAccessUiIntent(activityStarter, animationController, /* hasCard= */ true) } @Test @@ -184,9 +176,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun getPickerScreenState_unavailable() = testScope.runTest { - setUpState( - isWalletServiceAvailable = false, - ) + setUpState(isWalletServiceAvailable = false) assertThat(underTest.getPickerScreenState()) .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) @@ -195,9 +185,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun getPickerScreenState_disabledWhenTheFeatureIsNotEnabled() = testScope.runTest { - setUpState( - isWalletFeatureAvailable = false, - ) + setUpState(isWalletFeatureAvailable = false) assertThat(underTest.getPickerScreenState()) .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java) @@ -206,9 +194,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun getPickerScreenState_disabledWhenThereIsNoCard() = testScope.runTest { - setUpState( - hasSelectedCard = false, - ) + setUpState(hasSelectedCard = false) assertThat(underTest.getPickerScreenState()) .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java) @@ -219,7 +205,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { isWalletServiceAvailable: Boolean = true, isWalletQuerySuccessful: Boolean = true, hasSelectedCard: Boolean = true, - cardType: Int = WalletCard.CARD_TYPE_UNKNOWN + cardType: Int = WalletCard.CARD_TYPE_UNKNOWN, ) { val walletClient: QuickAccessWalletClient = mock() whenever(walletClient.tileIcon).thenReturn(ICON) @@ -242,11 +228,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { /*cardType= */ cardType, /*cardImage= */ mock(), /*contentDescription= */ CARD_DESCRIPTION, - /*pendingIntent= */ mock() + /*pendingIntent= */ mock(), ) .build() ), - 0 + 0, ) } else { GetWalletCardsResponse(emptyList(), 0) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index 1582e4776e15..a1018187df86 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -22,6 +22,7 @@ import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory @@ -84,16 +85,11 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { context = context, userFileManager = mock<UserFileManager>().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) + whenever(getSharedPreferences(anyString(), anyInt(), anyInt())) .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) client1 = FakeCustomizationProviderClient() @@ -103,9 +99,8 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { scope = testScope.backgroundScope, userTracker = userTracker, clientFactory = - FakeKeyguardQuickAffordanceProviderClientFactory( - userTracker, - ) { selectedUserId -> + FakeKeyguardQuickAffordanceProviderClientFactory(userTracker) { selectedUserId + -> when (selectedUserId) { SECONDARY_USER_1 -> client1 SECONDARY_USER_2 -> client2 @@ -115,10 +110,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { userHandle = UserHandle.SYSTEM, ) - overrideResource( - R.array.config_keyguardQuickAffordanceDefaults, - arrayOf<String>(), - ) + overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>()) underTest = KeyguardQuickAffordanceRepository( @@ -155,30 +147,19 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { val slotId2 = "slot2" underTest.setSelections(slotId1, listOf(config1.key)) - assertSelections( - configsBySlotId(), - mapOf( - slotId1 to listOf(config1), - ), - ) + assertSelections(configsBySlotId(), mapOf(slotId1 to listOf(config1))) underTest.setSelections(slotId2, listOf(config2.key)) assertSelections( configsBySlotId(), - mapOf( - slotId1 to listOf(config1), - slotId2 to listOf(config2), - ), + mapOf(slotId1 to listOf(config1), slotId2 to listOf(config2)), ) underTest.setSelections(slotId1, emptyList()) underTest.setSelections(slotId2, listOf(config1.key)) assertSelections( configsBySlotId(), - mapOf( - slotId1 to emptyList(), - slotId2 to listOf(config1), - ), + mapOf(slotId1 to emptyList(), slotId2 to listOf(config1)), ) } @@ -209,28 +190,15 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { val slot3 = "slot3" context.orCreateTestableResources.addOverride( R.array.config_keyguardQuickAffordanceSlots, - arrayOf( - "$slot1:2", - "$slot2:4", - "$slot3:5", - ), + arrayOf("$slot1:2", "$slot2:4", "$slot3:5"), ) assertThat(underTest.getSlotPickerRepresentations()) .isEqualTo( listOf( - KeyguardSlotPickerRepresentation( - id = slot1, - maxSelectedAffordances = 2, - ), - KeyguardSlotPickerRepresentation( - id = slot2, - maxSelectedAffordances = 4, - ), - KeyguardSlotPickerRepresentation( - id = slot3, - maxSelectedAffordances = 5, - ), + KeyguardSlotPickerRepresentation(id = slot1, maxSelectedAffordances = 2), + KeyguardSlotPickerRepresentation(id = slot2, maxSelectedAffordances = 4), + KeyguardSlotPickerRepresentation(id = slot3, maxSelectedAffordances = 5), ) ) } @@ -243,28 +211,15 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { val slot3 = "slot3" context.orCreateTestableResources.addOverride( R.array.config_keyguardQuickAffordanceSlots, - arrayOf( - "$slot1:2", - "$slot2:4", - "$slot3:5", - ), + arrayOf("$slot1:2", "$slot2:4", "$slot3:5"), ) assertThat(underTest.getSlotPickerRepresentations()) .isEqualTo( listOf( - KeyguardSlotPickerRepresentation( - id = slot3, - maxSelectedAffordances = 5, - ), - KeyguardSlotPickerRepresentation( - id = slot2, - maxSelectedAffordances = 4, - ), - KeyguardSlotPickerRepresentation( - id = slot1, - maxSelectedAffordances = 2, - ), + KeyguardSlotPickerRepresentation(id = slot3, maxSelectedAffordances = 5), + KeyguardSlotPickerRepresentation(id = slot2, maxSelectedAffordances = 4), + KeyguardSlotPickerRepresentation(id = slot1, maxSelectedAffordances = 2), ) ) } @@ -275,21 +230,9 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { userTracker.set( userInfos = listOf( - UserInfo( - UserHandle.USER_SYSTEM, - "Primary", - /* flags= */ 0, - ), - UserInfo( - SECONDARY_USER_1, - "Secondary 1", - /* flags= */ 0, - ), - UserInfo( - SECONDARY_USER_2, - "Secondary 2", - /* flags= */ 0, - ), + UserInfo(UserHandle.USER_SYSTEM, "Primary", /* flags= */ 0), + UserInfo(SECONDARY_USER_1, "Secondary 1", /* flags= */ 0), + UserInfo(SECONDARY_USER_2, "Secondary 2", /* flags= */ 0), ), selectedUserIndex = 2, ) @@ -302,12 +245,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { assertSelections( observed = observed(), expected = - mapOf( - KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to - listOf( - config2, - ), - ) + mapOf(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to listOf(config2)), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 46d1ebe75899..fe9da0ddb3c1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.dock.DockManager @@ -147,6 +148,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = @@ -196,6 +198,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = kosmos.testDispatcher, appContext = context, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = { kosmos.sceneInteractor }, ) kosmos.keyguardQuickAffordanceInteractor = underTest @@ -764,6 +767,28 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { assertThat(launchingAffordance).isFalse() } + @Test + fun onQuickAffordanceTriggered_updatesLaunchingFromTriggeredResult() = + testScope.runTest { + // WHEN selecting and triggering a quick affordance at a slot + val key = homeControls.key + val slot = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + val encodedKey = "$slot::$key" + val actionLaunched = true + homeControls.onTriggeredResult = + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(actionLaunched) + underTest.select(slot, key) + runCurrent() + underTest.onQuickAffordanceTriggered(encodedKey, expandable = null, slot) + + // THEN the latest triggered result shows that an action launched for the same key and + // slot + val launchingFromTriggeredResult by + collectLastValue(underTest.launchingFromTriggeredResult) + assertThat(launchingFromTriggeredResult?.launched).isEqualTo(actionLaunched) + assertThat(launchingFromTriggeredResult?.configKey).isEqualTo(encodedKey) + } + companion object { private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337 private val ICON: Icon = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt index ad5eeabf83d2..26fe379f00bf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -118,6 +119,50 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() { ) } + /** STL: Ls -> overlay, then settle with Idle(overlay). */ + @Test + fun transition_overlay_from_ls_scene_end_in_gone() = + testScope.runTest { + sceneTransitions.value = + ObservableTransitionState.Transition.ShowOrHideOverlay( + overlay = Overlays.NotificationsShade, + fromContent = Scenes.Lockscreen, + toContent = Overlays.NotificationsShade, + currentScene = Scenes.Lockscreen, + currentOverlays = flowOf(emptySet()), + progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + previewProgress = flowOf(0f), + isInPreviewStage = flowOf(false), + ) + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition(step = currentStep!!, state = TransitionState.RUNNING, progress = 0.4f) + + sceneTransitions.value = + ObservableTransitionState.Idle( + Scenes.Lockscreen, + setOf(Overlays.NotificationsShade), + ) + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + /** * STL: Ls -> Gone, then settle with Idle(Ls). KTF in this scenario needs to invert the * transition LS -> UNDEFINED to UNDEFINED -> LS as there is no mechanism in KTF to @@ -259,6 +304,47 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() { ) } + /** STL: Ls with overlay, then settle with Idle(Ls). */ + @Test + fun transition_overlay_to_ls_scene_end_in_ls() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = + ObservableTransitionState.Transition.ShowOrHideOverlay( + overlay = Overlays.NotificationsShade, + fromContent = Overlays.NotificationsShade, + toContent = Scenes.Lockscreen, + currentScene = Scenes.Lockscreen, + currentOverlays = flowOf(setOf(Overlays.NotificationsShade)), + progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + previewProgress = flowOf(0f), + isInPreviewStage = flowOf(false), + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition(step = currentStep!!, state = TransitionState.RUNNING, progress = 0.4f) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + /** STL: Gone -> Ls (AOD), will transition to AOD once */ @Test fun transition_to_ls_scene_with_changed_next_scene_is_respected_just_once() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt index 0e3b03f74c02..be504cc0f704 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt @@ -18,11 +18,8 @@ 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 as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.DisableSceneContainer @@ -75,7 +72,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { private val burnInFlow = MutableStateFlow(BurnInModel()) @Before - @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) @DisableSceneContainer fun setUp() { MockitoAnnotations.initMocks(this) @@ -219,50 +215,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun translationAndScale_whenFullyDozing_MigrationFlagOff_staysOutOfTopInset() = - testScope.runTest { - underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80)) - val movement by collectLastValue(underTest.movement) - assertThat(movement?.translationX).isEqualTo(0) - - // Set to dozing (on AOD) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 1f, - transitionState = TransitionState.FINISHED, - ), - validateStep = false, - ) - - // Trigger a change to the burn-in model - burnInFlow.value = BurnInModel(translationX = 20, translationY = -30, scale = 0.5f) - assertThat(movement?.translationX).isEqualTo(20) - // -20 instead of -30, due to inset of 80 - assertThat(movement?.translationY).isEqualTo(-20) - assertThat(movement?.scale).isEqualTo(0.5f) - assertThat(movement?.scaleClockOnly).isEqualTo(true) - - // Set to the beginning of GONE->AOD transition - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - value = 0f, - transitionState = TransitionState.STARTED, - ), - validateStep = false, - ) - assertThat(movement?.translationX).isEqualTo(0) - assertThat(movement?.translationY).isEqualTo(0) - assertThat(movement?.scale).isEqualTo(1f) - assertThat(movement?.scaleClockOnly).isEqualTo(true) - } - - @Test - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_whenFullyDozing_MigrationFlagOn_staysOutOfTopInset() = testScope.runTest { underTest.updateBurnInParams(burnInParameters.copy(minViewY = 100, topInset = 80)) @@ -334,7 +286,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { @Test @DisableSceneContainer - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_sceneContainerOff_weatherLargeClock() = testBurnInViewModelForClocks( isSmallClock = false, @@ -344,7 +295,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { @Test @DisableSceneContainer - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_sceneContainerOff_weatherSmallClock() = testBurnInViewModelForClocks( isSmallClock = true, @@ -354,7 +304,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { @Test @DisableSceneContainer - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_sceneContainerOff_nonWeatherLargeClock() = testBurnInViewModelForClocks( isSmallClock = false, @@ -364,7 +313,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { @Test @DisableSceneContainer - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun translationAndScale_sceneContainerOff_nonWeatherSmallClock() = testBurnInViewModelForClocks( isSmallClock = true, @@ -373,7 +321,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { ) @Test - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) @EnableSceneContainer fun translationAndScale_sceneContainerOn_weatherLargeClock() = testBurnInViewModelForClocks( @@ -383,7 +330,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { ) @Test - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) @EnableSceneContainer fun translationAndScale_sceneContainerOn_weatherSmallClock() = testBurnInViewModelForClocks( @@ -393,7 +339,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { ) @Test - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) @EnableSceneContainer fun translationAndScale_sceneContainerOn_nonWeatherLargeClock() = testBurnInViewModelForClocks( @@ -403,7 +348,6 @@ class AodBurnInViewModelTest : SysuiTestCase() { ) @Test - @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) @EnableSceneContainer @Ignore("b/367659687") fun translationAndScale_sceneContainerOn_nonWeatherSmallClock() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index 95ffc962797d..789477e38b55 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -19,12 +19,10 @@ package com.android.systemui.keyguard.ui.viewmodel -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.view.View import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState -import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.shared.model.CommunalScenes @@ -73,7 +71,6 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) -@EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java index 004aeb069a14..3d9fb0a9be16 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/FgsManagerControllerTest.java @@ -56,6 +56,7 @@ import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.settings.UserTracker; +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -84,6 +85,7 @@ public class FgsManagerControllerTest extends SysuiTestCase { FakeExecutor mMainExecutor; FakeExecutor mBackgroundExecutor; DeviceConfigProxyFake mDeviceConfigProxyFake; + FakeShadeDialogContextInteractor mFakeShadeDialogContextInteractor; @Mock IActivityManager mIActivityManager; @@ -118,6 +120,7 @@ public class FgsManagerControllerTest extends SysuiTestCase { public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); + mFakeShadeDialogContextInteractor = new FakeShadeDialogContextInteractor(mContext); mDeviceConfigProxyFake = new DeviceConfigProxyFake(); mSystemClock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(mSystemClock); @@ -346,7 +349,6 @@ public class FgsManagerControllerTest extends SysuiTestCase { SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, "true", false); FgsManagerController fmc = new FgsManagerControllerImpl( - mContext, mContext.getResources(), mMainExecutor, mBackgroundExecutor, @@ -359,7 +361,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDialogTransitionAnimator, mBroadcastDispatcher, mDumpManager, - mSystemUIDialogFactory + mSystemUIDialogFactory, + mFakeShadeDialogContextInteractor ); fmc.init(); Assert.assertTrue(fmc.getIncludesUserVisibleJobs()); @@ -374,7 +377,6 @@ public class FgsManagerControllerTest extends SysuiTestCase { SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, "false", false); fmc = new FgsManagerControllerImpl( - mContext, mContext.getResources(), mMainExecutor, mBackgroundExecutor, @@ -387,7 +389,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDialogTransitionAnimator, mBroadcastDispatcher, mDumpManager, - mSystemUIDialogFactory + mSystemUIDialogFactory, + mFakeShadeDialogContextInteractor ); fmc.init(); Assert.assertFalse(fmc.getIncludesUserVisibleJobs()); @@ -487,7 +490,6 @@ public class FgsManagerControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(BroadcastReceiver.class); FgsManagerController result = new FgsManagerControllerImpl( - mContext, mContext.getResources(), mMainExecutor, mBackgroundExecutor, @@ -500,7 +502,8 @@ public class FgsManagerControllerTest extends SysuiTestCase { mDialogTransitionAnimator, mBroadcastDispatcher, mDumpManager, - mSystemUIDialogFactory + mSystemUIDialogFactory, + mFakeShadeDialogContextInteractor ); result.init(); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt index a8e390c25a4d..a8e390c25a4d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt index fbbdc46a7873..0e823ccf1df5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt @@ -36,6 +36,7 @@ import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIconWithRes import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.policy.DataSaverController import com.android.systemui.util.mockito.whenever @@ -96,6 +97,7 @@ class DataSaverTileTest(flags: FlagsParameterization) : SysuiTestCase() { dataSaverController, mDialogTransitionAnimator, systemUIDialogFactory, + FakeShadeDialogContextInteractor(mContext), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt index 056efb34a0b1..c47a412e226a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt @@ -117,7 +117,6 @@ class QSTileViewModelImplTest : SysuiTestCase() { "test_spec:\n" + " QSTileState(" + "icon=Resource(res=0, contentDescription=Resource(res=0)), " + - "iconRes=null, " + "label=test_data, " + "activationState=INACTIVE, " + "secondaryLabel=null, " + diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java index b88861756889..5c6657b98801 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java @@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -231,7 +232,8 @@ public class InternetAdapterTest extends SysuiTestCase { mViewHolder.onWifiClick(mWifiEntry, mock(View.class)); - verify(mSpyContext).startActivity(any()); + verify(mInternetDialogController).startActivityForDialog(any()); + verify(mSpyContext, never()).startActivity(any()); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/AirplaneModeMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/AirplaneModeMapperTest.kt index 00460bfe83b2..557f4ea262a3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/AirplaneModeMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/AirplaneModeMapperTest.kt @@ -93,8 +93,7 @@ class AirplaneModeMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.airplane_mode) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt index 632aae035ede..24e46686e23d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt @@ -178,8 +178,7 @@ class AlarmTileMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.status_bar_alarm) return QSTileState( - Icon.Loaded(context.getDrawable(R.drawable.ic_alarm)!!, null), - R.drawable.ic_alarm, + Icon.Loaded(context.getDrawable(R.drawable.ic_alarm)!!, null, R.drawable.ic_alarm), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt index 5385f945946c..2ddaddd5ad35 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapperTest.kt @@ -253,8 +253,7 @@ class BatterySaverTileMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.battery_detail_switch_title) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt index 356b98eb192e..a3c159820a94 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt @@ -77,8 +77,11 @@ class ColorCorrectionTileMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.quick_settings_color_correction_label) return QSTileState( - Icon.Loaded(context.getDrawable(R.drawable.ic_qs_color_correction)!!, null), - R.drawable.ic_qs_color_correction, + Icon.Loaded( + context.getDrawable(R.drawable.ic_qs_color_correction)!!, + null, + R.drawable.ic_qs_color_correction, + ), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt index 8236c4c1e638..608adf183163 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt @@ -253,7 +253,6 @@ class CustomTileMapperTest : SysuiTestCase() { ): QSTileState { return QSTileState( icon?.let { com.android.systemui.common.shared.model.Icon.Loaded(icon, null) }, - null, "test label", activationState, "test subtitle", diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt index 587585ccee2e..a115c1235210 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapperTest.kt @@ -73,7 +73,11 @@ class FlashlightMapperTest : SysuiTestCase() { mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(true)) val expectedIcon = - Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, null) + Icon.Loaded( + context.getDrawable(R.drawable.qs_flashlight_icon_on)!!, + null, + R.drawable.qs_flashlight_icon_on, + ) val actualIcon = tileState.icon assertThat(actualIcon).isEqualTo(expectedIcon) } @@ -84,7 +88,11 @@ class FlashlightMapperTest : SysuiTestCase() { mapper.map(qsTileConfig, FlashlightTileModel.FlashlightAvailable(false)) val expectedIcon = - Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) + Icon.Loaded( + context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, + null, + R.drawable.qs_flashlight_icon_off, + ) val actualIcon = tileState.icon assertThat(actualIcon).isEqualTo(expectedIcon) } @@ -95,7 +103,11 @@ class FlashlightMapperTest : SysuiTestCase() { mapper.map(qsTileConfig, FlashlightTileModel.FlashlightTemporarilyUnavailable) val expectedIcon = - Icon.Loaded(context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, null) + Icon.Loaded( + context.getDrawable(R.drawable.qs_flashlight_icon_off)!!, + null, + R.drawable.qs_flashlight_icon_off, + ) val actualIcon = tileState.icon assertThat(actualIcon).isEqualTo(expectedIcon) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapperTest.kt index e81771ec38d5..8f8f7105415f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapperTest.kt @@ -58,8 +58,11 @@ class FontScalingTileMapperTest : SysuiTestCase() { private fun createFontScalingTileState(): QSTileState = QSTileState( - Icon.Loaded(context.getDrawable(R.drawable.ic_qs_font_scaling)!!, null), - R.drawable.ic_qs_font_scaling, + Icon.Loaded( + context.getDrawable(R.drawable.ic_qs_font_scaling)!!, + null, + R.drawable.ic_qs_font_scaling, + ), context.getString(R.string.quick_settings_font_scaling_label), QSTileState.ActivationState.ACTIVE, null, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapperTest.kt index 12d604ff6a7c..3d3447da15a1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapperTest.kt @@ -102,8 +102,7 @@ class HearingDevicesTileMapperTest : SysuiTestCase() { val label = context.getString(R.string.quick_settings_hearing_devices_label) val iconRes = R.drawable.qs_hearing_devices_icon return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt index 9dcf49e02697..b087bbc29bf7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt @@ -82,7 +82,6 @@ class InternetTileMapperTest : SysuiTestCase() { QSTileState.ActivationState.ACTIVE, context.getString(R.string.quick_settings_networks_available), Icon.Loaded(signalDrawable, null), - null, context.getString(R.string.quick_settings_internet_label), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) @@ -120,8 +119,11 @@ class InternetTileMapperTest : SysuiTestCase() { createInternetTileState( QSTileState.ActivationState.ACTIVE, inputModel.secondaryLabel.loadText(context).toString(), - Icon.Loaded(context.getDrawable(expectedSatIcon!!.res)!!, null), - expectedSatIcon.res, + Icon.Loaded( + context.getDrawable(expectedSatIcon!!.res)!!, + null, + expectedSatIcon.res, + ), expectedSatIcon.contentDescription.loadContentDescription(context).toString(), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) @@ -144,8 +146,7 @@ class InternetTileMapperTest : SysuiTestCase() { createInternetTileState( QSTileState.ActivationState.ACTIVE, context.getString(R.string.quick_settings_networks_available), - Icon.Loaded(context.getDrawable(wifiRes)!!, contentDescription = null), - wifiRes, + Icon.Loaded(context.getDrawable(wifiRes)!!, null, wifiRes), context.getString(R.string.quick_settings_internet_label), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) @@ -171,8 +172,8 @@ class InternetTileMapperTest : SysuiTestCase() { Icon.Loaded( context.getDrawable(R.drawable.ic_qs_no_internet_unavailable)!!, contentDescription = null, + R.drawable.ic_qs_no_internet_unavailable, ), - R.drawable.ic_qs_no_internet_unavailable, context.getString(R.string.quick_settings_networks_unavailable), ) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) @@ -182,13 +183,11 @@ class InternetTileMapperTest : SysuiTestCase() { activationState: QSTileState.ActivationState, secondaryLabel: String, icon: Icon, - iconRes: Int? = null, contentDescription: String, ): QSTileState { val label = context.getString(R.string.quick_settings_internet_label) return QSTileState( icon, - iconRes, label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt index 30fce73e04da..780d58c83e5b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt @@ -90,8 +90,7 @@ class ColorInversionTileMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.quick_settings_inversion_label) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt index 37e8a6053682..4ebe23dcdef1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapperTest.kt @@ -69,7 +69,12 @@ class LocationTileMapperTest : SysuiTestCase() { fun mapsEnabledDataToOnIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(true)) - val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_on)!!, null) + val expectedIcon = + Icon.Loaded( + context.getDrawable(R.drawable.qs_location_icon_on)!!, + null, + R.drawable.qs_location_icon_on, + ) val actualIcon = tileState.icon Truth.assertThat(actualIcon).isEqualTo(expectedIcon) } @@ -78,7 +83,12 @@ class LocationTileMapperTest : SysuiTestCase() { fun mapsDisabledDataToOffIconState() { val tileState: QSTileState = mapper.map(qsTileConfig, LocationTileModel(false)) - val expectedIcon = Icon.Loaded(context.getDrawable(R.drawable.qs_location_icon_off)!!, null) + val expectedIcon = + Icon.Loaded( + context.getDrawable(R.drawable.qs_location_icon_off)!!, + null, + R.drawable.qs_location_icon_off, + ) val actualIcon = tileState.icon Truth.assertThat(actualIcon).isEqualTo(expectedIcon) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt index de3dc5730421..44e6b4d2d0f6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt @@ -28,6 +28,7 @@ import com.android.internal.R import com.android.settingslib.notification.modes.TestModeBuilder import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestableContext +import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.asIcon import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues @@ -63,7 +64,7 @@ class ModesTileDataInteractorTest : SysuiTestCase() { fun setUp() { context.orCreateTestableResources.apply { addOverride(MODES_DRAWABLE_ID, MODES_DRAWABLE) - addOverride(R.drawable.ic_zen_mode_type_bedtime, BEDTIME_DRAWABLE) + addOverride(BEDTIME_DRAWABLE_ID, BEDTIME_DRAWABLE) } val customPackageContext = SysuiTestableContext(context) @@ -145,24 +146,24 @@ class ModesTileDataInteractorTest : SysuiTestCase() { // Tile starts with the generic Modes icon. runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) // Add an inactive mode -> Still modes icon zenModeRepository.addMode(id = "Mode", active = false) runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) // Add an active mode with a default icon: icon should be the mode icon, and the // iconResId is also populated, because we know it's a system icon. zenModeRepository.addMode( id = "Bedtime with default icon", type = AutomaticZenRule.TYPE_BEDTIME, - active = true + active = true, ) runCurrent() assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON) - assertThat(tileData?.iconResId).isEqualTo(R.drawable.ic_zen_mode_type_bedtime) + assertThat(tileData?.icon!!.res).isEqualTo(BEDTIME_DRAWABLE_ID) // Add another, less-prioritized mode that has a *custom* icon: for now, icon should // remain the first mode icon @@ -177,20 +178,20 @@ class ModesTileDataInteractorTest : SysuiTestCase() { ) runCurrent() assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON) - assertThat(tileData?.iconResId).isEqualTo(R.drawable.ic_zen_mode_type_bedtime) + assertThat(tileData?.icon!!.res).isEqualTo(BEDTIME_DRAWABLE_ID) // Deactivate more important mode: icon should be the less important, still active mode // And because it's a package-provided icon, iconResId is not populated. zenModeRepository.deactivateMode("Bedtime with default icon") runCurrent() assertThat(tileData?.icon).isEqualTo(CUSTOM_ICON) - assertThat(tileData?.iconResId).isNull() + assertThat(tileData?.icon!!.res).isNull() // Deactivate remaining mode: back to the default modes icon zenModeRepository.deactivateMode("Driving with custom icon") runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) } @Test @@ -205,18 +206,18 @@ class ModesTileDataInteractorTest : SysuiTestCase() { runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) // Activate a Mode -> Icon doesn't change. zenModeRepository.addMode(id = "Mode", active = true) runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) zenModeRepository.deactivateMode(id = "Mode") runCurrent() assertThat(tileData?.icon).isEqualTo(MODES_ICON) - assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID) + assertThat(tileData?.icon!!.res).isEqualTo(MODES_DRAWABLE_ID) } @EnableFlags(Flags.FLAG_MODES_UI) @@ -256,15 +257,17 @@ class ModesTileDataInteractorTest : SysuiTestCase() { val TEST_USER = UserHandle.of(1)!! const val CUSTOM_PACKAGE = "com.some.mode.owner.package" - val MODES_DRAWABLE_ID = R.drawable.ic_zen_priority_modes + const val MODES_DRAWABLE_ID = R.drawable.ic_zen_priority_modes const val CUSTOM_DRAWABLE_ID = 12345 + const val BEDTIME_DRAWABLE_ID = R.drawable.ic_zen_mode_type_bedtime + val MODES_DRAWABLE = TestStubDrawable("modes_icon") val BEDTIME_DRAWABLE = TestStubDrawable("bedtime") val CUSTOM_DRAWABLE = TestStubDrawable("custom") - val MODES_ICON = MODES_DRAWABLE.asIcon() - val BEDTIME_ICON = BEDTIME_DRAWABLE.asIcon() + val MODES_ICON = Icon.Loaded(MODES_DRAWABLE, null, MODES_DRAWABLE_ID) + val BEDTIME_ICON = Icon.Loaded(BEDTIME_DRAWABLE, null, BEDTIME_DRAWABLE_ID) val CUSTOM_ICON = CUSTOM_DRAWABLE.asIcon() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt index 88b00468573f..04e094f25f5d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt @@ -156,6 +156,10 @@ class ModesTileUserActionInteractorTest : SysuiTestCase() { } private fun modelOf(isActivated: Boolean, activeModeNames: List<String>): ModesTileModel { - return ModesTileModel(isActivated, activeModeNames, TestStubDrawable("icon").asIcon(), 123) + return ModesTileModel( + isActivated, + activeModeNames, + TestStubDrawable("icon").asIcon(res = 123), + ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt index 4e91d16bf1ec..d73044f6b479 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt @@ -99,18 +99,11 @@ class ModesTileMapperTest : SysuiTestCase() { @Test fun state_modelHasIconResId_includesIconResId() { - val icon = TestStubDrawable("res123").asIcon() - val model = - ModesTileModel( - isActivated = false, - activeModes = emptyList(), - icon = icon, - iconResId = 123, - ) + val icon = TestStubDrawable("res123").asIcon(res = 123) + val model = ModesTileModel(isActivated = false, activeModes = emptyList(), icon = icon) val state = underTest.map(config, model) assertThat(state.icon).isEqualTo(icon) - assertThat(state.iconRes).isEqualTo(123) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapperTest.kt index 1457f533f5ec..7c853261aa1c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapperTest.kt @@ -289,8 +289,7 @@ class NightDisplayTileMapperTest : SysuiTestCase() { if (TextUtils.isEmpty(secondaryLabel)) label else TextUtils.concat(label, ", ", secondaryLabel) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapperTest.kt index 2ac3e081b8f4..b6caa22a3012 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapperTest.kt @@ -58,8 +58,11 @@ class NotesTileMapperTest : SysuiTestCase() { private fun createNotesTileState(): QSTileState = QSTileState( - Icon.Loaded(context.getDrawable(R.drawable.ic_qs_notes)!!, null), - R.drawable.ic_qs_notes, + Icon.Loaded( + context.getDrawable(R.drawable.ic_qs_notes)!!, + null, + R.drawable.ic_qs_notes, + ), context.getString(R.string.quick_settings_notes_label), QSTileState.ActivationState.INACTIVE, /* secondaryLabel= */ null, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt index 7782d2b279a8..5b39810e3477 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapperTest.kt @@ -66,11 +66,7 @@ class OneHandedModeTileMapperTest : SysuiTestCase() { val outputState = mapper.map(config, inputModel) val expectedState = - createOneHandedModeTileState( - QSTileState.ActivationState.INACTIVE, - subtitleArray[1], - com.android.internal.R.drawable.ic_qs_one_handed_mode, - ) + createOneHandedModeTileState(QSTileState.ActivationState.INACTIVE, subtitleArray[1]) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } @@ -81,23 +77,21 @@ class OneHandedModeTileMapperTest : SysuiTestCase() { val outputState = mapper.map(config, inputModel) val expectedState = - createOneHandedModeTileState( - QSTileState.ActivationState.ACTIVE, - subtitleArray[2], - com.android.internal.R.drawable.ic_qs_one_handed_mode, - ) + createOneHandedModeTileState(QSTileState.ActivationState.ACTIVE, subtitleArray[2]) QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) } private fun createOneHandedModeTileState( activationState: QSTileState.ActivationState, secondaryLabel: String, - iconRes: Int, ): QSTileState { val label = context.getString(R.string.quick_settings_onehanded_label) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded( + context.getDrawable(com.android.internal.R.drawable.ic_qs_one_handed_mode)!!, + null, + com.android.internal.R.drawable.ic_qs_one_handed_mode, + ), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt index ed33250a3392..c572ff60b61a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapperTest.kt @@ -93,8 +93,8 @@ class QRCodeScannerTileMapperTest : SysuiTestCase() { Icon.Loaded( context.getDrawable(com.android.systemui.res.R.drawable.ic_qr_code_scanner)!!, null, + com.android.systemui.res.R.drawable.ic_qr_code_scanner, ), - com.android.systemui.res.R.drawable.ic_qr_code_scanner, label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt index 85111fd07663..00017f9059de 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapperTest.kt @@ -85,8 +85,7 @@ class ReduceBrightColorsTileMapperTest : SysuiTestCase() { R.drawable.qs_extra_dim_icon_on else R.drawable.qs_extra_dim_icon_off return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, context.resources diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt index 53671ba38eb6..74010143166b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt @@ -180,8 +180,7 @@ class RotationLockTileMapperTest : SysuiTestCase() { ): QSTileState { val label = context.getString(R.string.quick_settings_rotation_unlocked_label) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt index 9a450653aa8f..1fb5048dd4c9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapperTest.kt @@ -91,8 +91,7 @@ class DataSaverTileMapperTest : SysuiTestCase() { else context.resources.getStringArray(R.array.tile_states_saver)[0] return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt index cd683c44a59c..363255695131 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/ui/ScreenRecordTileMapperTest.kt @@ -110,8 +110,7 @@ class ScreenRecordTileMapperTest : SysuiTestCase() { val label = context.getString(R.string.quick_settings_screen_record_label) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapperTest.kt index c569403960d0..e4cd0e0ec215 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapperTest.kt @@ -146,8 +146,7 @@ class SensorPrivacyToggleTileMapperTest : SysuiTestCase() { else context.getString(R.string.quick_settings_mic_label) return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt index 0d2ebe42b7ad..8f5f2d3e6689 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapperTest.kt @@ -69,8 +69,7 @@ class UiModeNightTileMapperTest : SysuiTestCase() { expandedAccessibilityClass: KClass<out View>? = Switch::class, ): QSTileState { return QSTileState( - Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes, + Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label, activationState, secondaryLabel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt index 86321ea04703..2c81f39a03ec 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapperTest.kt @@ -109,8 +109,7 @@ class WorkModeTileMapperTest : SysuiTestCase() { val label = testLabel val iconRes = com.android.internal.R.drawable.stat_sys_managed_profile_status return QSTileState( - icon = Icon.Loaded(context.getDrawable(iconRes)!!, null), - iconRes = iconRes, + icon = Icon.Loaded(context.getDrawable(iconRes)!!, null, iconRes), label = label, activationState = activationState, secondaryLabel = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt index 039a1dc05c79..518a0a5a1446 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.PseudoGridView import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.qs.tiles.UserDetailView +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq @@ -84,6 +85,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { mDialogTransitionAnimator, uiEventLogger, dialogFactory, + FakeShadeDialogContextInteractor(mContext), ) } @@ -91,32 +93,32 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun showDialog_callsDialogShow() { val launchController = mock<DialogTransitionAnimator.Controller>() `when`(launchExpandable.dialogTransitionController(any())).thenReturn(launchController) - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(mDialogTransitionAnimator).show(eq(dialog), eq(launchController), anyBoolean()) verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) } @Test fun dialog_showForAllUsers() { - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(dialog).setShowForAllUsers(true) } @Test fun dialog_cancelOnTouchOutside() { - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(dialog).setCanceledOnTouchOutside(true) } @Test fun adapterAndGridLinked() { - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>()) } @Test fun doneButtonLogsCorrectly() { - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor)) @@ -129,7 +131,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun clickSettingsButton_noFalsing_opensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(dialog) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) @@ -150,7 +152,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun clickSettingsButton_Falsing_notOpensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) - controller.showDialog(context, launchExpandable) + controller.showDialog(launchExpandable) verify(dialog) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index e56b965d9402..3187cca6ca45 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -37,7 +37,6 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.bouncerSceneContentViewModel -import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.EnableSceneContainer @@ -48,9 +47,9 @@ import com.android.systemui.keyguard.ui.viewmodel.lockscreenUserActionsViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.currentValue -import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.verifyCurrent import com.android.systemui.lifecycle.activateIn import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest @@ -77,12 +76,9 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch 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.Mockito.verify /** * Integration test cases for the Scene Framework. @@ -137,10 +133,10 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { sceneContainerViewModel.activateIn(testScope) assertWithMessage("Initial scene key mismatch!") - .that(sceneContainerViewModel.currentScene.value) + .that(currentValue(sceneContainerViewModel.currentScene)) .isEqualTo(sceneContainerConfig.initialSceneKey) assertWithMessage("Initial scene container visibility mismatch!") - .that(sceneContainerViewModel.isVisible) + .that(currentValue { sceneContainerViewModel.isVisible }) .isTrue() } @@ -337,7 +333,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { .that(bouncerActionButton) .isNotNull() kosmos.bouncerSceneContentViewModel.onActionButtonClicked(bouncerActionButton!!) - runCurrent() // TODO(b/369765704): Assert that an activity was started once we use ActivityStarter. } @@ -358,9 +353,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { .that(bouncerActionButton) .isNotNull() kosmos.bouncerSceneContentViewModel.onActionButtonClicked(bouncerActionButton!!) - runCurrent() - verify(mockTelecomManager).showInCallScreen(any()) + verifyCurrent(mockTelecomManager).showInCallScreen(any()) } @Test @@ -413,7 +407,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { * the UI must gradually transition between scenes. */ private fun Kosmos.getCurrentSceneInUi(): SceneKey { - return when (val state = transitionState.value) { + return when (val state = currentValue(transitionState)) { is ObservableTransitionState.Idle -> state.currentScene is ObservableTransitionState.Transition.ChangeScene -> state.fromScene is ObservableTransitionState.Transition.ShowOrHideOverlay -> state.currentScene @@ -436,7 +430,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { // is not an observable that can trigger a new evaluation. fakeDeviceEntryRepository.setLockscreenEnabled(enableLockscreen) fakeAuthenticationRepository.setAuthenticationMethod(authMethod) - testScope.runCurrent() } /** Emulates a phone call in progress. */ @@ -447,7 +440,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { setIsInCall(true) setCallState(TelephonyManager.CALL_STATE_OFFHOOK) } - testScope.runCurrent() } /** @@ -480,24 +472,21 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) - testScope.runCurrent() // Report progress of transition. - while (progressFlow.value < 1f) { + while (currentValue(progressFlow) < 1f) { progressFlow.value += 0.2f - testScope.runCurrent() } // End the transition and report the change. transitionState.value = ObservableTransitionState.Idle(to) fakeSceneDataSource.unpause(force = true) - testScope.runCurrent() assertWithMessage("Visibility mismatch after scene transition from $from to $to!") - .that(sceneContainerViewModel.isVisible) + .that(currentValue { sceneContainerViewModel.isVisible }) .isEqualTo(expectedVisible) - assertThat(sceneContainerViewModel.currentScene.value).isEqualTo(to) + assertThat(currentValue(sceneContainerViewModel.currentScene)).isEqualTo(to) bouncerSceneJob = if (to == Scenes.Bouncer) { @@ -510,7 +499,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { bouncerSceneJob?.cancel() null } - testScope.runCurrent() } /** @@ -556,13 +544,12 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { ) powerInteractor.setAwakeForTest() - testScope.runCurrent() } /** Unlocks the device by entering the correct PIN. Ends up in the Gone scene. */ private fun Kosmos.unlockDevice() { assertWithMessage("Cannot unlock a device that's already unlocked!") - .that(deviceEntryInteractor.isUnlocked.value) + .that(currentValue(deviceEntryInteractor.isUnlocked)) .isFalse() emulateUserDrivenTransition(Scenes.Bouncer) @@ -595,7 +582,6 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { pinBouncerViewModel.onPinButtonClicked(digit) } pinBouncerViewModel.onAuthenticateButtonClicked() - testScope.runCurrent() } /** @@ -625,26 +611,23 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { } pinBouncerViewModel.onAuthenticateButtonClicked() fakeMobileConnectionsRepository.isAnySimSecure.value = false - testScope.runCurrent() setAuthMethod(authMethodAfterSimUnlock, enableLockscreen) - testScope.runCurrent() } /** Changes device wakefulness state from asleep to awake, going through intermediary states. */ private fun Kosmos.wakeUpDevice() { - val wakefulnessModel = powerInteractor.detailedWakefulness.value + val wakefulnessModel = currentValue(powerInteractor.detailedWakefulness) assertWithMessage("Cannot wake up device as it's already awake!") .that(wakefulnessModel.isAwake()) .isFalse() powerInteractor.setAwakeForTest() - testScope.runCurrent() } /** Changes device wakefulness state from awake to asleep, going through intermediary states. */ private suspend fun Kosmos.putDeviceToSleep(waitForLock: Boolean = true) { - val wakefulnessModel = powerInteractor.detailedWakefulness.value + val wakefulnessModel = currentValue(powerInteractor.detailedWakefulness) assertWithMessage("Cannot put device to sleep as it's already asleep!") .that(wakefulnessModel.isAwake()) .isTrue() @@ -659,22 +642,18 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { ) .toLong() ) - } else { - testScope.runCurrent() } } /** Emulates the dismissal of the IME (soft keyboard). */ private fun Kosmos.dismissIme() { - (bouncerSceneContentViewModel.authMethodViewModel.value as? PasswordBouncerViewModel)?.let { - it.onImeDismissed() - testScope.runCurrent() - } + (currentValue(bouncerSceneContentViewModel.authMethodViewModel) + as? PasswordBouncerViewModel) + ?.let { it.onImeDismissed() } } private fun Kosmos.introduceLockedSim() { setAuthMethod(AuthenticationMethodModel.Sim) fakeMobileConnectionsRepository.isAnySimSecure.value = true - testScope.runCurrent() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index d3b58287e961..07a408b9a4d7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -45,7 +45,6 @@ import android.annotation.IdRes; import android.content.ContentResolver; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; @@ -57,7 +56,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewPropertyAnimator; -import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityManager; @@ -74,10 +72,8 @@ import com.android.keyguard.KeyguardSliceViewController; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; -import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.keyguard.logging.KeyguardLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; @@ -147,12 +143,13 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger; import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository; import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor; import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; +import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -172,17 +169,13 @@ import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ScrimController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.ShadeTouchableRegionManager; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.TapAgainViewController; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; -import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; import com.android.systemui.statusbar.policy.SplitShadeStateController; import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository; @@ -227,8 +220,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected HeadsUpManager mHeadsUpManager; @Mock protected NotificationGutsManager mGutsManager; @Mock protected KeyguardStatusBarView mKeyguardStatusBar; - @Mock protected KeyguardUserSwitcherView mUserSwitcherView; - @Mock protected ViewStub mUserSwitcherStubView; @Mock protected HeadsUpTouchHelper.Callback mHeadsUpCallback; @Mock protected KeyguardUpdateMonitor mUpdateMonitor; @Mock protected KeyguardBypassController mKeyguardBypassController; @@ -254,12 +245,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected ConversationNotificationManager mConversationNotificationManager; @Mock protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock protected KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - @Mock protected KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; - @Mock protected KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent; - @Mock protected KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; - @Mock protected KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; - @Mock protected KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent; - @Mock protected KeyguardUserSwitcherController mKeyguardUserSwitcherController; @Mock protected KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock protected KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; @Mock protected KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; @@ -477,9 +462,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); when(mView.getContext()).thenReturn(getContext()); when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar); - when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView); - when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn( - mUserSwitcherStubView); when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch); when(mView.findViewById(R.id.notification_stack_scroller)) .thenReturn(mNotificationStackScrollLayout); @@ -511,14 +493,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager); FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder( mDisplayMetrics); - when(mKeyguardQsUserSwitchComponentFactory.build(any())) - .thenReturn(mKeyguardQsUserSwitchComponent); - when(mKeyguardQsUserSwitchComponent.getKeyguardQsUserSwitchController()) - .thenReturn(mKeyguardQsUserSwitchController); - when(mKeyguardUserSwitcherComponentFactory.build(any())) - .thenReturn(mKeyguardUserSwitcherComponent); - when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController()) - .thenReturn(mKeyguardUserSwitcherController); when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true); when(mQs.getView()).thenReturn(mView); when(mQSFragment.getView()).thenReturn(mView); @@ -627,8 +601,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { .thenReturn(mKeyguardStatusBarViewController); when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean())) .thenReturn(keyguardStatusView); - when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean())) - .thenReturn(mUserSwitcherView); when(mNotificationRemoteInputManager.isRemoteInputActive()) .thenReturn(false); doAnswer(invocation -> { @@ -690,8 +662,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mNotificationsQSContainerController, mNotificationStackScrollLayoutController, mKeyguardStatusViewComponentFactory, - mKeyguardQsUserSwitchComponentFactory, - mKeyguardUserSwitcherComponentFactory, mKeyguardStatusBarViewComponentFactory, mLockscreenShadeTransitionController, mAuthController, @@ -883,16 +853,6 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mNotificationPanelViewController.updateResources(); } - protected void updateMultiUserSetting(boolean enabled) { - when(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)).thenReturn(false); - when(mUserManager.isUserSwitcherEnabled(false)).thenReturn(enabled); - final ArgumentCaptor<ContentObserver> observerCaptor = - ArgumentCaptor.forClass(ContentObserver.class); - verify(mContentResolver) - .registerContentObserver(any(), anyBoolean(), observerCaptor.capture()); - observerCaptor.getValue().onChange(/* selfChange */ false); - } - protected void updateSmallestScreenWidth(int smallestScreenWidthDp) { Configuration configuration = new Configuration(); configuration.smallestScreenWidthDp = smallestScreenWidthDp; diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 550fcf78d857..51f00a09ff43 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -16,59 +16,28 @@ package com.android.systemui.shade; -import static com.android.keyguard.KeyguardClockSwitch.LARGE; -import static com.android.keyguard.KeyguardClockSwitch.SMALL; -import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; -import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN; -import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPENING; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; -import static com.android.systemui.statusbar.StatusBarState.SHADE; -import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; import static com.google.common.truth.Truth.assertThat; -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.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.animation.Animator; -import android.animation.ValueAnimator; -import android.graphics.Point; -import android.os.PowerManager; -import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; -import androidx.constraintlayout.widget.ConstraintSet; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.DejankUtils; import com.android.systemui.flags.DisableSceneContainer; -import com.android.systemui.flags.Flags; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.power.domain.interactor.PowerInteractor; -import com.android.systemui.res.R; -import com.android.systemui.statusbar.notification.row.ExpandableView; -import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener; -import com.android.systemui.statusbar.notification.stack.AmbientState; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm; import com.google.android.msdl.data.model.MSDLToken; @@ -76,10 +45,6 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; - -import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) @@ -91,83 +56,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo DejankUtils.setImmediate(true); } - /** - * When the Back gesture starts (progress 0%), the scrim will stay at 100% scale (1.0f). - */ - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testBackGesture_min_scrimAtMaxScale() { - mNotificationPanelViewController.onBackProgressed(0.0f); - verify(mScrimController).applyBackScaling(1.0f); - } - - /** - * When the Back gesture is at max (progress 100%), the scrim will be scaled to its minimum. - */ - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testBackGesture_max_scrimAtMinScale() { - mNotificationPanelViewController.onBackProgressed(1.0f); - verify(mScrimController).applyBackScaling( - NotificationPanelViewController.SHADE_BACK_ANIM_MIN_SCALE); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onNotificationHeightChangeWhileOnKeyguardWillComputeMaxKeyguardNotifications() { - mStatusBarStateController.setState(KEYGUARD); - ArgumentCaptor<OnHeightChangedListener> captor = - ArgumentCaptor.forClass(OnHeightChangedListener.class); - verify(mNotificationStackScrollLayoutController) - .setOnHeightChangedListener(captor.capture()); - OnHeightChangedListener listener = captor.getValue(); - - clearInvocations(mNotificationStackSizeCalculator); - listener.onHeightChanged(mock(ExpandableView.class), false); - - verify(mNotificationStackSizeCalculator) - .computeMaxKeyguardNotifications(any(), anyFloat(), anyFloat(), anyFloat()); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onNotificationHeightChangeWhileInShadeWillNotComputeMaxKeyguardNotifications() { - mStatusBarStateController.setState(SHADE); - ArgumentCaptor<OnHeightChangedListener> captor = - ArgumentCaptor.forClass(OnHeightChangedListener.class); - verify(mNotificationStackScrollLayoutController) - .setOnHeightChangedListener(captor.capture()); - OnHeightChangedListener listener = captor.getValue(); - - clearInvocations(mNotificationStackSizeCalculator); - listener.onHeightChanged(mock(ExpandableView.class), false); - - verify(mNotificationStackSizeCalculator, never()) - .computeMaxKeyguardNotifications(any(), anyFloat(), anyFloat(), anyFloat()); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void computeMaxKeyguardNotifications_lockscreenToShade_returnsExistingMax() { - when(mAmbientState.getFractionToShade()).thenReturn(0.5f); - mNotificationPanelViewController.setMaxDisplayedNotifications(-1); - - // computeMaxKeyguardNotifications sets maxAllowed to 0 at minimum if it updates the value - assertThat(mNotificationPanelViewController.computeMaxKeyguardNotifications()) - .isEqualTo(-1); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void computeMaxKeyguardNotifications_noTransition_updatesMax() { - when(mAmbientState.getFractionToShade()).thenReturn(0f); - mNotificationPanelViewController.setMaxDisplayedNotifications(-1); - - // computeMaxKeyguardNotifications sets maxAllowed to 0 at minimum if it updates the value - assertThat(mNotificationPanelViewController.computeMaxKeyguardNotifications()) - .isNotEqualTo(-1); - } - @Test @Ignore("b/261472011 - Test appears inconsistent across environments") public void getVerticalSpaceForLockscreenNotifications_useLockIconBottomPadding_returnsSpaceAvailable() { @@ -205,165 +93,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getVerticalSpaceForLockscreenShelf_useLockIconBottomPadding_returnsShelfHeight() { - enableSplitShade(/* enabled= */ false); - setBottomPadding(/* stackScrollLayoutBottom= */ 100, - /* lockIconPadding= */ 20, - /* indicationPadding= */ 0, - /* ambientPadding= */ 0); - - when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5); - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(5); - - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(5); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getVerticalSpaceForLockscreenShelf_useIndicationBottomPadding_returnsZero() { - enableSplitShade(/* enabled= */ false); - setBottomPadding(/* stackScrollLayoutBottom= */ 100, - /* lockIconPadding= */ 0, - /* indicationPadding= */ 30, - /* ambientPadding= */ 0); - - when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5); - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getVerticalSpaceForLockscreenShelf_useAmbientBottomPadding_returnsZero() { - enableSplitShade(/* enabled= */ false); - setBottomPadding(/* stackScrollLayoutBottom= */ 100, - /* lockIconPadding= */ 0, - /* indicationPadding= */ 0, - /* ambientPadding= */ 40); - - when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5); - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getVerticalSpaceForLockscreenShelf_useLockIconPadding_returnsLessThanShelfHeight() { - enableSplitShade(/* enabled= */ false); - setBottomPadding(/* stackScrollLayoutBottom= */ 100, - /* lockIconPadding= */ 10, - /* indicationPadding= */ 8, - /* ambientPadding= */ 0); - - when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5); - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(2); - - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(2); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getVerticalSpaceForLockscreenShelf_splitShade() { - enableSplitShade(/* enabled= */ true); - setBottomPadding(/* stackScrollLayoutBottom= */ 100, - /* lockIconPadding= */ 10, - /* indicationPadding= */ 8, - /* ambientPadding= */ 0); - - when(mNotificationStackScrollLayoutController.getShelfHeight()).thenReturn(5); - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - - assertThat(mNotificationPanelViewController.getVerticalSpaceForLockscreenShelf()) - .isEqualTo(0); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSetPanelScrimMinFractionWhenHeadsUpIsDragged() { - mNotificationPanelViewController.setHeadsUpDraggingStartingHeight( - mNotificationPanelViewController.getMaxPanelHeight() / 2); - verify(mNotificationShadeDepthController).setPanelPullDownMinFraction(eq(0.5f)); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSetDozing_notifiesNsslAndStateController() { - mNotificationPanelViewController.setDozing(true /* dozing */, false /* animate */); - verify(mNotificationStackScrollLayoutController).setDozing(eq(true), eq(false)); - assertThat(mStatusBarStateController.getDozeAmount()).isEqualTo(1f); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testOnDozeAmountChanged_positionClockAndNotificationsUsesUdfpsLocation() { - // GIVEN UDFPS is enrolled and we're on the keyguard - final Point udfpsLocationCenter = new Point(0, 100); - final float udfpsRadius = 10f; - when(mUpdateMonitor.isUdfpsEnrolled()).thenReturn(true); - when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocationCenter); - when(mAuthController.getUdfpsRadius()).thenReturn(udfpsRadius); - mNotificationPanelViewController.getStatusBarStateListener().onStateChanged(KEYGUARD); - - // WHEN the doze amount changes - mNotificationPanelViewController.mClockPositionAlgorithm = mock( - KeyguardClockPositionAlgorithm.class); - mNotificationPanelViewController.getStatusBarStateListener().onDozeAmountChanged(1f, 1f); - - // THEN the clock positions accounts for the UDFPS location & its worst case burn in - final float udfpsTop = udfpsLocationCenter.y - udfpsRadius - mMaxUdfpsBurnInOffsetY; - verify(mNotificationPanelViewController.mClockPositionAlgorithm).setup( - anyInt(), - anyFloat(), - anyInt(), - anyInt(), - anyInt(), - /* darkAmount */ eq(1f), - anyFloat(), - anyBoolean(), - anyInt(), - anyFloat(), - anyInt(), - anyBoolean(), - /* udfpsTop */ eq(udfpsTop), - anyFloat(), - anyBoolean() - ); - } - - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSetExpandedHeight() { - mNotificationPanelViewController.setExpandedHeight(200); - assertThat((int) mNotificationPanelViewController.getExpandedHeight()).isEqualTo(200); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testOnTouchEvent_expansionCanBeBlocked() { - onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)); - onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 200f, 0)); - assertThat((int) mNotificationPanelViewController.getExpandedHeight()).isEqualTo(200); - - mNotificationPanelViewController.blockExpansionForCurrentTouch(); - onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 300f, 0)); - // Expansion should not have changed because it was blocked - assertThat((int) mNotificationPanelViewController.getExpandedHeight()).isEqualTo(200); - } - - @Test @EnableFlags(com.android.systemui.Flags.FLAG_SHADE_EXPANDS_ON_STATUS_BAR_LONG_PRESS) public void onStatusBarLongPress_shadeExpands() { long downTime = 42L; @@ -422,71 +151,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void test_pulsing_onTouchEvent_noTracking() { - // GIVEN device is pulsing - mNotificationPanelViewController.setPulsing(true); - - // WHEN touch DOWN & MOVE events received - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, - 0 /* metaState */)); - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_MOVE, 0f /* x */, 200f /* y */, - 0 /* metaState */)); - - // THEN touch is NOT tracked (since the device is pulsing) - assertThat(mNotificationPanelViewController.isTracking()).isFalse(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void alternateBouncerVisible_onTouchEvent_notHandled() { - // GIVEN alternate bouncer is visible - when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); - - // WHEN touch DOWN event received; THEN touch is NOT handled - assertThat(onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, - 0 /* metaState */))).isFalse(); - - // WHEN touch MOVE event received; THEN touch is NOT handled - assertThat(onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_MOVE, 0f /* x */, 200f /* y */, - 0 /* metaState */))).isFalse(); - - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void test_onTouchEvent_startTracking() { - // GIVEN device is NOT pulsing - mNotificationPanelViewController.setPulsing(false); - - // WHEN touch DOWN & MOVE events received - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, - 0 /* metaState */)); - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_MOVE, 0f /* x */, 200f /* y */, - 0 /* metaState */)); - - // THEN touch is tracked - assertThat(mNotificationPanelViewController.isTracking()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onInterceptTouchEvent_nsslMigrationOff_userActivity() { - mTouchHandler.onInterceptTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, - 0 /* metaState */)); - - verify(mCentralSurfaces).userActivity(); - } - - @Test - @EnableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) public void onInterceptTouchEvent_nsslMigrationOn_userActivity_not_called() { mTouchHandler.onInterceptTouchEvent(MotionEvent.obtain(0L /* downTime */, 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, @@ -496,279 +160,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testOnTouchEvent_expansionResumesAfterBriefTouch() { - mFalsingManager.setIsClassifierEnabled(true); - mFalsingManager.setIsFalseTouch(false); - mNotificationPanelViewController.setForceFlingAnimationForTest(true); - // Start shade collapse with swipe up - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, - 0 /* metaState */)); - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_MOVE, 0f /* x */, 300f /* y */, - 0 /* metaState */)); - onTouchEvent(MotionEvent.obtain(0L /* downTime */, - 0L /* eventTime */, MotionEvent.ACTION_UP, 0f /* x */, 300f /* y */, - 0 /* metaState */)); - - assertThat(mNotificationPanelViewController.isClosing()).isTrue(); - assertThat(mNotificationPanelViewController.isFlinging()).isTrue(); - - // simulate touch that does not exceed touch slop - onTouchEvent(MotionEvent.obtain(2L /* downTime */, - 2L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 300f /* y */, - 0 /* metaState */)); - - mNotificationPanelViewController.setTouchSlopExceeded(false); - - onTouchEvent(MotionEvent.obtain(2L /* downTime */, - 2L /* eventTime */, MotionEvent.ACTION_UP, 0f /* x */, 300f /* y */, - 0 /* metaState */)); - - // fling should still be called after a touch that does not exceed touch slop - assertThat(mNotificationPanelViewController.isClosing()).isTrue(); - assertThat(mNotificationPanelViewController.isFlinging()).isTrue(); - mNotificationPanelViewController.setForceFlingAnimationForTest(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testA11y_initializeNode() { - AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo(); - mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo); - - List<AccessibilityNodeInfo.AccessibilityAction> actionList = nodeInfo.getActionList(); - assertThat(actionList).containsAtLeastElementsIn( - new AccessibilityNodeInfo.AccessibilityAction[] { - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD, - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP} - ); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testA11y_scrollForward() { - mAccessibilityDelegate.performAccessibilityAction( - mView, - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId(), - null); - - verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testA11y_scrollUp() { - mAccessibilityDelegate.performAccessibilityAction( - mView, - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId(), - null); - - verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testKeyguardStatusViewInSplitShade_changesConstraintsDependingOnNotifications() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mNotificationPanelViewController.updateResources(); - assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) - .isEqualTo(R.id.qs_edge_guideline); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - mNotificationPanelViewController.updateResources(); - assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd) - .isEqualTo(ConstraintSet.PARENT_ID); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_splitShade_dozing_alwaysDozingOn_isCentered() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - setDozing(/* dozing= */ true, /* dozingAlwaysOn= */ true); - - assertKeyguardStatusViewCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_splitShade_dozing_alwaysDozingOff_isNotCentered() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - setDozing(/* dozing= */ true, /* dozingAlwaysOn= */ false); - - assertKeyguardStatusViewNotCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_splitShade_notDozing_alwaysDozingOn_isNotCentered() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ true); - - assertKeyguardStatusViewNotCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_splitShade_pulsing_isNotCentered() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); - - assertKeyguardStatusViewNotCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_splitShade_notPulsing_isNotCentered() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); - - assertKeyguardStatusViewNotCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_singleShade_isCentered() { - enableSplitShade(/* enabled= */ false); - // The conditions below would make the clock NOT be centered on split shade. - // On single shade it should always be centered though. - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); - - assertKeyguardStatusViewCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenNot() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true); - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); - assertKeyguardStatusViewCentered(); - - mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(false); - assertKeyguardStatusViewNotCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_willPlayDelayedDoze_notifiesKeyguardMediaController() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true); - - verify(mKeyguardMediaController).setDozeWakeUpAnimationWaiting(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenStillCenteredIfNoNotifs() { - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - - mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true); - setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false); - assertKeyguardStatusViewCentered(); - - mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(false); - assertKeyguardStatusViewCentered(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onKeyguardStatusViewHeightChange_animatesNextTopPaddingChangeForNSSL() { - ArgumentCaptor<View.OnLayoutChangeListener> captor = - ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); - verify(mKeyguardStatusView).addOnLayoutChangeListener(captor.capture()); - View.OnLayoutChangeListener listener = captor.getValue(); - - clearInvocations(mNotificationStackScrollLayoutController); - - when(mKeyguardStatusView.getHeight()).thenReturn(0); - listener.onLayoutChange(mKeyguardStatusView, /* left= */ 0, /* top= */ 0, /* right= */ - 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */ - 0, /* oldBottom = */ 200); - - verify(mNotificationStackScrollLayoutController).animateNextTopPaddingChange(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testCanCollapsePanelOnTouch_trueForKeyGuard() { - mStatusBarStateController.setState(KEYGUARD); - - assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testCanCollapsePanelOnTouch_trueWhenScrolledToBottom() { - mStatusBarStateController.setState(SHADE); - when(mNotificationStackScrollLayoutController.isScrolledToBottom()).thenReturn(true); - - assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testCanCollapsePanelOnTouch_trueWhenInSettings() { - mStatusBarStateController.setState(SHADE); - when(mQsController.getExpanded()).thenReturn(true); - - assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testCanCollapsePanelOnTouch_falseInDualPaneShade() { - mStatusBarStateController.setState(SHADE); - enableSplitShade(/* enabled= */ true); - when(mQsController.getExpanded()).thenReturn(true); - - assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse(); - } - - @Test @Ignore("b/341163515 - fails to clean up animators correctly") public void testSwipeWhileLocked_notifiesKeyguardState() { mStatusBarStateController.setState(KEYGUARD); @@ -786,515 +177,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testCancelSwipeWhileLocked_notifiesKeyguardState() { - mStatusBarStateController.setState(KEYGUARD); - - // Fling expanded (cancelling the keyguard exit swipe). We should notify keyguard state that - // the fling occurred and did not dismiss the keyguard. - mNotificationPanelViewController.flingToHeight( - 0f, true /* expand */, 1000f, 1f, false); - mNotificationPanelViewController.cancelHeightAnimator(); - verify(mKeyguardStateController).notifyPanelFlingEnd(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSwipe_exactlyToTarget_notifiesNssl() { - // No over-expansion - mNotificationPanelViewController.setOverExpansion(0f); - // Fling to a target that is equal to the current position (i.e. a no-op fling). - mNotificationPanelViewController.flingToHeight( - 0f, - true, - mNotificationPanelViewController.getExpandedHeight(), - 1f, - false); - // Verify that the NSSL is notified that the panel is *not* flinging. - verify(mNotificationStackScrollLayoutController).setPanelFlinging(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testRotatingToSplitShadeWithQsExpanded_transitionsToShadeLocked() { - mStatusBarStateController.setState(KEYGUARD); - when(mQsController.getExpanded()).thenReturn(true); - - enableSplitShade(true); - - assertThat(mStatusBarStateController.getState()).isEqualTo(SHADE_LOCKED); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testUnlockedSplitShadeTransitioningToKeyguard_closesQS() { - enableSplitShade(true); - mStatusBarStateController.setState(SHADE); - mStatusBarStateController.setState(KEYGUARD); - - verify(mQsController).closeQs(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testLockedSplitShadeTransitioningToKeyguard_closesQS() { - enableSplitShade(true); - mStatusBarStateController.setState(SHADE_LOCKED); - mStatusBarStateController.setState(KEYGUARD); - - verify(mQsController).closeQs(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSwitchesToCorrectClockInSinglePaneShade() { - mStatusBarStateController.setState(KEYGUARD); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSwitchesToCorrectClockInSplitShade() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - clearInvocations(mKeyguardStatusViewController); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); - - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController, times(2)) - .displayClock(LARGE, /* animate */ true); - verify(mKeyguardStatusViewController, never()) - .displayClock(SMALL, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testHasNotifications_switchesToLargeClockWhenEnteringSplitShade() { - mStatusBarStateController.setState(KEYGUARD); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - - enableSplitShade(/* enabled= */ true); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testNoNotifications_switchesToLargeClockWhenEnteringSplitShade() { - mStatusBarStateController.setState(KEYGUARD); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - - enableSplitShade(/* enabled= */ true); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testHasNotifications_switchesToSmallClockWhenExitingSplitShade() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - clearInvocations(mKeyguardStatusViewController); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - - enableSplitShade(/* enabled= */ false); - - verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testNoNotifications_switchesToLargeClockWhenExitingSplitShade() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - clearInvocations(mKeyguardStatusViewController); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - - enableSplitShade(/* enabled= */ false); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void clockSize_mediaShowing_inSplitShade_onAod_isLarge() { - when(mDozeParameters.getAlwaysOn()).thenReturn(true); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - clearInvocations(mKeyguardStatusViewController); - - mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate= */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void clockSize_mediaShowing_inSplitShade_screenOff_notAod_isSmall() { - when(mDozeParameters.getAlwaysOn()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - clearInvocations(mKeyguardStatusViewController); - - mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); - - verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate= */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onQsSetExpansionHeightCalled_qsFullyExpandedOnKeyguard_showNSSL() { - // GIVEN - mStatusBarStateController.setState(KEYGUARD); - when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false); - when(mQsController.getFullyExpanded()).thenReturn(true); - when(mQsController.getExpanded()).thenReturn(true); - - // WHEN - int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - - // THEN - // We are interested in the last value of the stack alpha. - ArgumentCaptor<Float> alphaCaptor = ArgumentCaptor.forClass(Float.class); - verify(mNotificationStackScrollLayoutController, atLeastOnce()) - .setMaxAlphaForKeyguard(alphaCaptor.capture(), any()); - assertThat(alphaCaptor.getValue()).isEqualTo(1.0f); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onQsSetExpansionHeightCalled_qsFullyExpandedOnKeyguard_hideNSSL() { - // GIVEN - mStatusBarStateController.setState(KEYGUARD); - when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false); - when(mQsController.getFullyExpanded()).thenReturn(false); - when(mQsController.getExpanded()).thenReturn(true); - - // WHEN - int transitionDistance = mNotificationPanelViewController - .getMaxPanelTransitionDistance() / 2; - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - - // THEN - // We are interested in the last value of the stack alpha. - ArgumentCaptor<Float> alphaCaptor = ArgumentCaptor.forClass(Float.class); - verify(mNotificationStackScrollLayoutController, atLeastOnce()) - .setMaxAlphaForKeyguard(alphaCaptor.capture(), any()); - assertThat(alphaCaptor.getValue()).isEqualTo(0.0f); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testSwitchesToBigClockInSplitShadeOnAodAnimateDisabled() { - when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - clearInvocations(mKeyguardStatusViewController); - when(mMediaDataManager.hasActiveMedia()).thenReturn(true); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - - mNotificationPanelViewController.setDozing(true, false); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void switchesToBigClockInSplitShadeOn_landFlagOn_ForceSmallClock() { - when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ false); - mNotificationPanelViewController.setDozing(false, false); - mFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true); - when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); - when(mMediaDataManager.hasActiveMedia()).thenReturn(false); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - clearInvocations(mKeyguardStatusViewController); - - enableSplitShade(/* enabled= */ true); - mNotificationPanelViewController.updateResources(); - - verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void switchesToBigClockInSplitShadeOn_landFlagOff_DontForceSmallClock() { - when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(false); - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ false); - mNotificationPanelViewController.setDozing(false, false); - mFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false); - when(mResources.getBoolean(R.bool.force_small_clock_on_lockscreen)).thenReturn(true); - when(mMediaDataManager.hasActiveMedia()).thenReturn(false); - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - clearInvocations(mKeyguardStatusViewController); - - enableSplitShade(/* enabled= */ true); - mNotificationPanelViewController.updateResources(); - - verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(/* enabled= */ true); - clearInvocations(mKeyguardStatusViewController); - when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true); - - // one notification + media player visible - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(true); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate */ true); - - // only media player visible - when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0); - when(mActiveNotificationsInteractor.getAreAnyNotificationsPresentValue()).thenReturn(false); - triggerPositionClockAndNotifications(); - verify(mKeyguardStatusViewController, times(2)).displayClock(SMALL, true); - verify(mKeyguardStatusViewController, never()).displayClock(LARGE, /* animate */ true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testFoldToAodAnimationCleansupInAnimationEnd() { - ArgumentCaptor<Animator.AnimatorListener> animCaptor = - ArgumentCaptor.forClass(Animator.AnimatorListener.class); - ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> updateCaptor = - ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class); - - // Start fold animation & Capture Listeners - mNotificationPanelViewController.getShadeFoldAnimator() - .startFoldToAodAnimation(() -> {}, () -> {}, () -> {}); - verify(mViewPropertyAnimator).setListener(animCaptor.capture()); - verify(mViewPropertyAnimator).setUpdateListener(updateCaptor.capture()); - - // End animation and validate listeners were unset - animCaptor.getValue().onAnimationEnd(null); - verify(mViewPropertyAnimator).setListener(null); - verify(mViewPropertyAnimator).setUpdateListener(null); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testExpandWithQsMethodIsUsingLockscreenTransitionController() { - enableSplitShade(/* enabled= */ true); - mStatusBarStateController.setState(KEYGUARD); - - mNotificationPanelViewController.expandToQs(); - - verify(mLockscreenShadeTransitionController).goToLockedShade( - /* expandedView= */null, /* needsQSAnimation= */true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void setKeyguardStatusBarAlpha_setsAlphaOnKeyguardStatusBarController() { - float statusBarAlpha = 0.5f; - - mNotificationPanelViewController.setKeyguardStatusBarAlpha(statusBarAlpha); - - verify(mKeyguardStatusBarViewController).setAlpha(statusBarAlpha); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testQsToBeImmediatelyExpandedWhenOpeningPanelInSplitShade() { - enableSplitShade(/* enabled= */ true); - mShadeExpansionStateManager.updateState(STATE_OPEN); - verify(mQsController).setExpandImmediate(false); - - mShadeExpansionStateManager.updateState(STATE_CLOSED); - verify(mQsController, times(2)).setExpandImmediate(false); - - mShadeExpansionStateManager.updateState(STATE_OPENING); - verify(mQsController).setExpandImmediate(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testQsNotToBeImmediatelyExpandedWhenGoingFromUnlockedToLocked() { - enableSplitShade(/* enabled= */ true); - mShadeExpansionStateManager.updateState(STATE_CLOSED); - - mStatusBarStateController.setState(KEYGUARD); - // going to lockscreen would trigger STATE_OPENING - mShadeExpansionStateManager.updateState(STATE_OPENING); - - verify(mQsController, never()).setExpandImmediate(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testQsImmediateResetsWhenPanelOpensOrCloses() { - mShadeExpansionStateManager.updateState(STATE_OPEN); - mShadeExpansionStateManager.updateState(STATE_CLOSED); - verify(mQsController, times(2)).setExpandImmediate(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testQsExpansionChangedToDefaultWhenRotatingFromOrToSplitShade() { - when(mCommandQueue.panelsEnabled()).thenReturn(true); - - // to make sure shade is in expanded state - mNotificationPanelViewController.startInputFocusTransfer(); - - // switch to split shade from portrait (default state) - enableSplitShade(/* enabled= */ true); - verify(mQsController).setExpanded(true); - - // switch to portrait from split shade - enableSplitShade(/* enabled= */ false); - verify(mQsController).setExpanded(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void testPanelClosedWhenClosingQsInSplitShade() { - mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1, - /* expanded= */ true, /* tracking= */ false); - enableSplitShade(/* enabled= */ true); - mNotificationPanelViewController.setExpandedFraction(1f); - - assertThat(mNotificationPanelViewController.isClosing()).isFalse(); - mNotificationPanelViewController.animateCollapseQs(false); - - assertThat(mNotificationPanelViewController.isClosing()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getMaxPanelTransitionDistance_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() { - enableSplitShade(true); - mNotificationPanelViewController.expandToQs(); - - int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - - assertThat(maxDistance).isEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void isExpandingOrCollapsing_returnsTrue_whenQsLockscreenDragInProgress() { - when(mQsController.getLockscreenShadeDragProgress()).thenReturn(0.5f); - assertThat(mNotificationPanelViewController.isExpandingOrCollapsing()).isTrue(); - } - - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getMaxPanelTransitionDistance_inSplitShade_withHeadsUp_returnsBiggerValue() { - enableSplitShade(true); - mNotificationPanelViewController.expandToQs(); - when(mHeadsUpManager.isTrackingHeadsUp()).thenReturn(true); - when(mQsController.calculatePanelHeightExpanded(anyInt())).thenReturn(10000); - mNotificationPanelViewController.setHeadsUpDraggingStartingHeight( - SPLIT_SHADE_FULL_TRANSITION_DISTANCE); - - int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - - // make sure we're ignoring the placeholder value for Qs max height - assertThat(maxDistance).isLessThan(10000); - assertThat(maxDistance).isGreaterThan(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getMaxPanelTransitionDistance_expandingSplitShade_keyguard_returnsNonSplitShadeValue() { - mStatusBarStateController.setState(KEYGUARD); - enableSplitShade(true); - mNotificationPanelViewController.expandToQs(); - - int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - - assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getMaxPanelTransitionDistance_expanding_notSplitShade_returnsNonSplitShadeValue() { - enableSplitShade(false); - mNotificationPanelViewController.expandToQs(); - - int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - - assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() { - setIsFullWidth(true); - - verify(mQsController).setNotificationPanelFullWidth(true); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() { - setIsFullWidth(false); - - verify(mQsController).setNotificationPanelFullWidth(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onLayoutChange_qsNotSet_doesNotCrash() { - mQuickSettingsController.setQs(null); - - triggerLayoutChange(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onEmptySpaceClicked_notDozingAndOnKeyguard_requestsFaceAuth() { - StatusBarStateController.StateListener statusBarStateListener = - mNotificationPanelViewController.getStatusBarStateListener(); - statusBarStateListener.onStateChanged(KEYGUARD); - mNotificationPanelViewController.setDozing(false, false); - - // This sets the dozing state that is read when onMiddleClicked is eventually invoked. - mTouchHandler.onTouch(mock(View.class), mDownMotionEvent); - mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0); - - verify(mDeviceEntryFaceAuthInteractor).onNotificationPanelClicked(); - } - - @Test - @EnableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) public void nsslFlagEnabled_allowOnlyExternalTouches() { // This sets the dozing state that is read when onMiddleClicked is eventually invoked. @@ -1306,130 +188,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onSplitShadeChanged_duringShadeExpansion_resetsOverScrollState() { - // There was a bug where there was left-over overscroll state after going from split shade - // to single shade. - // Since on single shade we don't set overscroll values on QS nor Scrim, those values that - // were there from split shade were never reset. - // To prevent this, we will reset all overscroll state. - enableSplitShade(true); - reset(mQsController, mScrimController, mNotificationStackScrollLayoutController); - - mNotificationPanelViewController.setOverExpansion(123); - verify(mQsController).setOverScrollAmount(123); - verify(mScrimController).setNotificationsOverScrollAmount(123); - verify(mNotificationStackScrollLayoutController).setOverExpansion(123); - - enableSplitShade(false); - verify(mQsController).setOverScrollAmount(0); - verify(mScrimController).setNotificationsOverScrollAmount(0); - verify(mNotificationStackScrollLayoutController).setOverExpansion(0); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onSplitShadeChanged_alwaysResetsOverScrollState() { - enableSplitShade(true); - enableSplitShade(false); - - verify(mQsController, times(2)).setOverScrollAmount(0); - verify(mScrimController, times(2)).setNotificationsOverScrollAmount(0); - verify(mNotificationStackScrollLayoutController, times(2)).setOverExpansion(0); - verify(mNotificationStackScrollLayoutController, times(2)).setOverScrollAmount(0); - } - - /** - * When shade is flinging to close and this fling is not intercepted, - * {@link AmbientState#setIsClosing(boolean)} should be called before - * {@link NotificationStackScrollLayoutController#onExpansionStopped()} - * to ensure scrollY can be correctly set to be 0 - */ - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onShadeFlingClosingEnd_mAmbientStateSetClose_thenOnExpansionStopped() { - // Given: Shade is expanded - mNotificationPanelViewController.notifyExpandingFinished(); - mNotificationPanelViewController.setClosing(false); - - // When: Shade flings to close not canceled - mNotificationPanelViewController.notifyExpandingStarted(); - mNotificationPanelViewController.setClosing(true); - mNotificationPanelViewController.onFlingEnd(false); - - // Then: AmbientState's mIsClosing should be set to false - // before mNotificationStackScrollLayoutController.onExpansionStopped() is called - // to ensure NotificationStackScrollLayout.resetScrollPosition() -> resetScrollPosition - // -> setOwnScrollY(0) can set scrollY to 0 when shade is closed - InOrder inOrder = inOrder(mAmbientState, mNotificationStackScrollLayoutController); - inOrder.verify(mAmbientState).setIsClosing(false); - inOrder.verify(mNotificationStackScrollLayoutController).onExpansionStopped(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void onShadeFlingEnd_mExpandImmediateShouldBeReset() { - mNotificationPanelViewController.onFlingEnd(false); - - verify(mQsController).setExpandImmediate(false); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void inUnlockedSplitShade_transitioningMaxTransitionDistance_makesShadeFullyExpanded() { - mStatusBarStateController.setState(SHADE); - enableSplitShade(true); - int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isFullyExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeFullyExpanded_inShadeState() { - mStatusBarStateController.setState(SHADE); - - mNotificationPanelViewController.setExpandedHeight(0); - assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isFalse(); - - int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeFullyExpanded_onKeyguard() { - mStatusBarStateController.setState(KEYGUARD); - - int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isFalse(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeFullyExpanded_onShadeLocked() { - mStatusBarStateController.setState(SHADE_LOCKED); - assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeExpanded_whenHasHeight() { - int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance(); - mNotificationPanelViewController.setExpandedHeight(transitionDistance); - assertThat(mNotificationPanelViewController.isExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeExpanded_whenInstantExpanding() { - mNotificationPanelViewController.expand(true); - assertThat(mNotificationPanelViewController.isExpanded()).isTrue(); - } - - @Test @DisableSceneContainer public void shadeExpanded_whenHunIsPresent() { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); @@ -1437,84 +195,6 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeExpanded_whenUnlockedOffscreenAnimationRunning() { - when(mUnlockedScreenOffAnimationController.isAnimationPlaying()).thenReturn(true); - assertThat(mNotificationPanelViewController.isExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeExpanded_whenInputFocusTransferStarted() { - when(mCommandQueue.panelsEnabled()).thenReturn(true); - - mNotificationPanelViewController.startInputFocusTransfer(); - - assertThat(mNotificationPanelViewController.isExpanded()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void shadeNotExpanded_whenInputFocusTransferStartedButPanelsDisabled() { - when(mCommandQueue.panelsEnabled()).thenReturn(false); - - mNotificationPanelViewController.startInputFocusTransfer(); - - assertThat(mNotificationPanelViewController.isExpanded()).isFalse(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void cancelInputFocusTransfer_shadeCollapsed() { - when(mCommandQueue.panelsEnabled()).thenReturn(true); - mNotificationPanelViewController.startInputFocusTransfer(); - - mNotificationPanelViewController.cancelInputFocusTransfer(); - - assertThat(mNotificationPanelViewController.isExpanded()).isFalse(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void finishInputFocusTransfer_shadeFlingingOpen() { - when(mCommandQueue.panelsEnabled()).thenReturn(true); - mNotificationPanelViewController.startInputFocusTransfer(); - - mNotificationPanelViewController.finishInputFocusTransfer(/* velocity= */ 0f); - - assertThat(mNotificationPanelViewController.isFlinging()).isTrue(); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getFalsingThreshold_deviceNotInteractive_isQsThreshold() { - PowerInteractor.Companion.setAsleepForTest( - mPowerInteractor, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON); - when(mQsController.getFalsingThreshold()).thenReturn(14); - - assertThat(mNotificationPanelViewController.getFalsingThreshold()).isEqualTo(14); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getFalsingThreshold_lastWakeNotDueToTouch_isQsThreshold() { - PowerInteractor.Companion.setAwakeForTest( - mPowerInteractor, PowerManager.WAKE_REASON_POWER_BUTTON); - when(mQsController.getFalsingThreshold()).thenReturn(14); - - assertThat(mNotificationPanelViewController.getFalsingThreshold()).isEqualTo(14); - } - - @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - public void getFalsingThreshold_lastWakeDueToTouch_greaterThanQsThreshold() { - PowerInteractor.Companion.setAwakeForTest(mPowerInteractor, PowerManager.WAKE_REASON_TAP); - when(mQsController.getFalsingThreshold()).thenReturn(14); - - assertThat(mNotificationPanelViewController.getFalsingThreshold()).isGreaterThan(14); - } - - @Test @EnableFlags(com.android.systemui.Flags.FLAG_MSDL_FEEDBACK) public void performHapticFeedback_withMSDL_forGestureStart_deliversDragThresholdToken() { mNotificationPanelViewController diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt deleted file mode 100644 index 5289554e9e18..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(ExperimentalCoroutinesApi::class) - -package com.android.systemui.shade - -import android.platform.test.annotations.DisableFlags -import android.testing.TestableLooper -import android.view.HapticFeedbackConstants -import android.view.View -import android.view.ViewStub -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.internal.util.CollectionUtils -import com.android.keyguard.KeyguardClockSwitch.LARGE -import com.android.systemui.Flags -import com.android.systemui.res.R -import com.android.systemui.statusbar.StatusBarState.KEYGUARD -import com.android.systemui.statusbar.StatusBarState.SHADE -import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.cancelChildren -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.advanceUntilIdle -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.Captor -import org.mockito.Mockito.atLeastOnce -import org.mockito.Mockito.clearInvocations -import org.mockito.Mockito.never -import org.mockito.Mockito.times -import org.mockito.Mockito.verify - -@RunWith(AndroidJUnit4::class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) -@SmallTest -@DisableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) -class NotificationPanelViewControllerWithCoroutinesTest : - NotificationPanelViewControllerBaseTest() { - - @Captor private lateinit var viewCaptor: ArgumentCaptor<View> - - override fun getMainDispatcher() = Dispatchers.Main.immediate - - @Test - fun testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() = runTest { - launch(Dispatchers.Main.immediate) { givenViewAttached() } - advanceUntilIdle() - - whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher)) - .thenReturn(true) - updateMultiUserSetting(true) - clearInvocations(mView) - - updateMultiUserSetting(false) - - verify(mView, atLeastOnce()).addView(viewCaptor.capture(), anyInt()) - val userSwitcherStub = - CollectionUtils.find(viewCaptor.allValues) { view -> - view.id == R.id.keyguard_user_switcher_stub - } - assertThat(userSwitcherStub).isNotNull() - assertThat(userSwitcherStub).isInstanceOf(ViewStub::class.java) - } - - @Test - fun testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() = runTest { - launch(Dispatchers.Main.immediate) { givenViewAttached() } - advanceUntilIdle() - - whenever(mView.findViewById<View>(R.id.keyguard_user_switcher_view)).thenReturn(null) - updateSmallestScreenWidth(300) - whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher)) - .thenReturn(true) - whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)) - .thenReturn(false) - whenever(mUserManager.isUserSwitcherEnabled(false)).thenReturn(true) - - updateSmallestScreenWidth(800) - - verify(mUserSwitcherStubView).inflate() - } - - @Test - fun testFinishInflate_userSwitcherDisabled_doNotInflateUserSwitchView_initClock() = runTest { - launch(Dispatchers.Main.immediate) { givenViewAttached() } - advanceUntilIdle() - - whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher)) - .thenReturn(true) - whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)) - .thenReturn(false) - whenever(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */)) - .thenReturn(false) - - mNotificationPanelViewController.onFinishInflate() - - verify(mUserSwitcherStubView, never()).inflate() - verify(mKeyguardStatusViewController, times(3)).displayClock(LARGE, /* animate */ true) - - coroutineContext.cancelChildren() - } - - @Test - fun testReInflateViews_userSwitcherDisabled_doNotInflateUserSwitchView() = runTest { - launch(Dispatchers.Main.immediate) { givenViewAttached() } - advanceUntilIdle() - - whenever(mResources.getBoolean(com.android.internal.R.bool.config_keyguardUserSwitcher)) - .thenReturn(true) - whenever(mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)) - .thenReturn(false) - whenever(mUserManager.isUserSwitcherEnabled(false /* showEvenIfNotActionable */)) - .thenReturn(false) - - mNotificationPanelViewController.reInflateViews() - - verify(mUserSwitcherStubView, never()).inflate() - - coroutineContext.cancelChildren() - } - - @Test - fun testDoubleTapRequired_Keyguard() = runTest { - launch(Dispatchers.Main.immediate) { - val listener = getFalsingTapListener() - mStatusBarStateController.setState(KEYGUARD) - - listener.onAdditionalTapRequired() - - verify(mKeyguardIndicationController).showTransientIndication(anyInt()) - } - advanceUntilIdle() - } - - @Test - @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) - fun doubleTapRequired_onKeyguard_usesPerformHapticFeedback() = runTest { - launch(Dispatchers.Main.immediate) { - val listener = getFalsingTapListener() - mStatusBarStateController.setState(KEYGUARD) - - listener.onAdditionalTapRequired() - verify(mKeyguardIndicationController).showTransientIndication(anyInt()) - verify(mVibratorHelper) - .performHapticFeedback(eq(mView), eq(HapticFeedbackConstants.REJECT)) - } - advanceUntilIdle() - } - - @Test - fun testDoubleTapRequired_ShadeLocked() = runTest { - launch(Dispatchers.Main.immediate) { - val listener = getFalsingTapListener() - mStatusBarStateController.setState(SHADE_LOCKED) - - listener.onAdditionalTapRequired() - - verify(mTapAgainViewController).show() - } - advanceUntilIdle() - } - - @Test - @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) - fun doubleTapRequired_shadeLocked_usesPerformHapticFeedback() = runTest { - launch(Dispatchers.Main.immediate) { - val listener = getFalsingTapListener() - mStatusBarStateController.setState(SHADE_LOCKED) - - listener.onAdditionalTapRequired() - verify(mVibratorHelper) - .performHapticFeedback(eq(mView), eq(HapticFeedbackConstants.REJECT)) - - verify(mTapAgainViewController).show() - } - advanceUntilIdle() - } - - @Test - fun testOnAttachRefreshStatusBarState() = runTest { - launch(Dispatchers.Main.immediate) { - mStatusBarStateController.setState(KEYGUARD) - whenever(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(false) - mOnAttachStateChangeListeners.forEach { it.onViewAttachedToWindow(mView) } - verify(mKeyguardStatusViewController) - .setKeyguardStatusViewVisibility( - KEYGUARD /*statusBarState*/, - false /*keyguardFadingAway*/, - false /*goingToFullShade*/, - SHADE, /*oldStatusBarState*/ - ) - } - advanceUntilIdle() - } -} 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 929537dcf757..0361ffe475a2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -212,18 +212,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { } @Test - @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testDragDownHelperCalledWhenDraggingDown() = - testScope.runTest { - whenever(dragDownHelper.isDraggingDown).thenReturn(true) - val now = SystemClock.elapsedRealtime() - val ev = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0f, 0f, 0 /* meta */) - underTest.onTouchEvent(ev) - verify(dragDownHelper).onTouchEvent(ev) - ev.recycle() - } - - @Test fun testNoInterceptTouch() = testScope.runTest { captureInteractionEventHandler() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt index ad2b23e49536..a47db2ec728b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt @@ -118,12 +118,12 @@ class ShadeModeInteractorImplTest : SysuiTestCase() { } @Test - fun getTopEdgeSplitFraction_wideScreen_leftSideLarger() = + fun getTopEdgeSplitFraction_wideScreen_splitInHalf() = testScope.runTest { // Ensure isShadeLayoutWide is collected. val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide) kosmos.shadeRepository.setShadeLayoutWide(true) - assertThat(underTest.getTopEdgeSplitFraction()).isGreaterThan(0.5f) + assertThat(underTest.getTopEdgeSplitFraction()).isEqualTo(0.5f) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt index aa8b4f136683..4423426945eb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt @@ -117,7 +117,6 @@ class DefaultClockProviderTest : SysuiTestCase() { verify(mockLargeClockView).onTimeZoneChanged(notNull()) verify(mockSmallClockView).refreshTime() verify(mockLargeClockView).refreshTime() - verify(mockLargeClockView).setLayoutParams(any()) } @Test @@ -163,7 +162,6 @@ class DefaultClockProviderTest : SysuiTestCase() { clock.largeClock.events.onFontSettingChanged(200f) verify(mockLargeClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), eq(200f)) - verify(mockLargeClockView).setLayoutParams(any()) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt index 165e943a0cc0..40f13bbbf908 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt @@ -16,10 +16,12 @@ package com.android.systemui.statusbar.chips.notification.ui.viewmodel +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -71,6 +73,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_noNotifs_empty() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -81,6 +84,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_notifMissingStatusBarChipIconView_empty() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -99,6 +103,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_onePromotedNotif_statusBarIconViewMatches() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -122,6 +127,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { @Test @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_onePromotedNotif_connectedDisplaysFlagEnabled_statusBarIconMatches() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -145,6 +151,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_onePromotedNotif_colorMatches() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -175,6 +182,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_onlyForPromotedNotifs() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -208,6 +216,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { @Test @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_connectedDisplaysFlagEnabled_onlyForPromotedNotifs() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -242,6 +251,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_hasShortCriticalText_usesTextInsteadOfTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -272,6 +282,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_noTime_isIconOnly() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -294,6 +305,36 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @EnableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + fun chips_basicTime_hiddenIfAutomaticallyPromoted() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.time = + PromotedNotificationContentModel.When( + time = 6543L, + mode = PromotedNotificationContentModel.When.Mode.BasicTime, + ) + } + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = mock<StatusBarIconView>(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java) + } + + @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_basicTime_isShortTimeDelta() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -322,6 +363,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_countUpTime_isTimer() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -349,6 +391,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_countDownTime_isTimer() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -376,6 +419,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_noHeadsUp_showsTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -407,6 +451,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_hasHeadsUpByUser_onlyShowsIcon() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -442,6 +487,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_clickingChipNotifiesInteractor() = kosmos.runTest { val latest by collectLastValue(underTest.chips) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelperTest.kt new file mode 100644 index 000000000000..d727089094f0 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelperTest.kt @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.chips.ui.view + +import android.view.View +import android.widget.TextView +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.Before +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ChipTextTruncationHelperTest : SysuiTestCase() { + + val underTest by lazy { ChipTextTruncationHelper(TextView(context)) } + + @Before + fun setUp() { + mContext.getOrCreateTestableResources().apply { + this.addOverride(R.dimen.ongoing_activity_chip_max_text_width, MAX_WIDTH) + } + } + + @Test + fun shouldShowText_desiredLessThanMax_true() { + val result = + underTest.shouldShowText( + desiredTextWidthPx = MAX_WIDTH / 2, + widthMeasureSpec = UNLIMITED_WIDTH_SPEC, + ) + + assertThat(result).isTrue() + } + + @Test + fun shouldShowText_desiredSlightlyLargerThanMax_true() { + val result = + underTest.shouldShowText( + desiredTextWidthPx = (MAX_WIDTH * 1.1).toInt(), + widthMeasureSpec = UNLIMITED_WIDTH_SPEC, + ) + + assertThat(result).isTrue() + } + + @Test + fun shouldShowText_desiredMoreThanTwiceMax_false() { + val result = + underTest.shouldShowText( + desiredTextWidthPx = (MAX_WIDTH * 2.2).toInt(), + widthMeasureSpec = UNLIMITED_WIDTH_SPEC, + ) + + assertThat(result).isFalse() + } + + @Test + fun shouldShowText_widthSpecLessThanMax_usesWidthSpec() { + val smallerWidthSpec = + SysuiMeasureSpec( + View.MeasureSpec.makeMeasureSpec(MAX_WIDTH / 2, View.MeasureSpec.AT_MOST) + ) + + // WHEN desired is more than twice the smallerWidthSpec + val desiredWidth = (MAX_WIDTH * 1.1).toInt() + + val result = + underTest.shouldShowText( + desiredTextWidthPx = desiredWidth, + widthMeasureSpec = smallerWidthSpec, + ) + + // THEN returns false because smallerWidthSpec is used as the requirement + assertThat(result).isFalse() + } + + @Test + fun shouldShowText_maxLessThanWidthSpec_usesMax() { + val largerWidthSpec = + SysuiMeasureSpec( + View.MeasureSpec.makeMeasureSpec(MAX_WIDTH * 3, View.MeasureSpec.AT_MOST) + ) + + // WHEN desired is more than twice the max + val desiredWidth = (MAX_WIDTH * 2.2).toInt() + + val result = + underTest.shouldShowText( + desiredTextWidthPx = desiredWidth, + widthMeasureSpec = largerWidthSpec, + ) + + // THEN returns false because the max is used as the requirement + assertThat(result).isFalse() + } + + companion object { + private const val MAX_WIDTH = 200 + private val UNLIMITED_WIDTH_SPEC = + SysuiMeasureSpec(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt index 1a7c8a336c81..43bd7cf0bddb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt @@ -48,12 +48,14 @@ class ParseableCommandTest : SysuiTestCase() { val mySubCommand = object : ParseableCommand("subCommand") { val flag by flag("flag") + override fun execute(pw: PrintWriter) {} } val mySubCommand2 = object : ParseableCommand("subCommand2") { val flag by flag("flag") + override fun execute(pw: PrintWriter) {} } @@ -141,6 +143,7 @@ class ParseableCommandTest : SysuiTestCase() { val cmd = object : ParseableCommand("test-command") { val flag by flag("flag") + override fun execute(pw: PrintWriter) {} } @@ -162,6 +165,7 @@ class ParseableCommandTest : SysuiTestCase() { var onParseFailedCalled = false override fun execute(pw: PrintWriter) {} + override fun onParseFailed(error: ArgParseError) { onParseFailedCalled = true } @@ -204,11 +208,7 @@ class ParseableCommandTest : SysuiTestCase() { val cmd = object : ParseableCommand(name) { val singleRequiredParam: String by - param( - longName = "param1", - shortName = "p", - valueParser = Type.String, - ) + param(longName = "param1", shortName = "p", valueParser = Type.String) .required() override fun execute(pw: PrintWriter) {} @@ -253,6 +253,7 @@ class ParseableCommandTest : SysuiTestCase() { val cmd = object : ParseableCommand(name) { val subCmd by subCommand(subCmd) + override fun execute(pw: PrintWriter) {} } @@ -293,18 +294,72 @@ class ParseableCommandTest : SysuiTestCase() { assertThat(myCommand.subCommand?.param1).isEqualTo("arg2") } - class MyCommand( - private val onExecute: ((MyCommand) -> Unit)? = null, - ) : ParseableCommand(name) { + @Test + fun commandWithSubCommand_allOptional_nothingPassed_execCalled() { + // GIVEN single sub command + val subName = "sub-command" + val subCmd = + object : ParseableCommand(subName) { + var execd = false + + override fun execute(pw: PrintWriter) { + execd = true + } + } + + // GIVEN command wrapping the optional subcommand + val cmd = + object : ParseableCommand(name) { + val sub: ParseableCommand? by subCommand(subCmd) + var execCalled = false + + override fun execute(pw: PrintWriter) { + execCalled = true + } + } + + // WHEN the base command is sent (i.e., sub-command is missing + cmd.execute(pw, listOf()) + // THEN exec is still called, since this is a valid command + assertThat(cmd.execCalled).isTrue() + } + + @Test + fun commandWithSubCommand_required_nothingPassed_execNotCalled() { + // GIVEN single sub command + val subName = "sub-command" + val subCmd = + object : ParseableCommand(subName) { + var execd = false + + override fun execute(pw: PrintWriter) { + execd = true + } + } + + // GIVEN command wrapping the required subcommand + val cmd = + object : ParseableCommand(name) { + val sub: ParseableCommand? by subCommand(subCmd).required() + var execCalled = false + + override fun execute(pw: PrintWriter) { + execCalled = true + } + } + + // WHEN the base command is sent (i.e., sub-command is missing + cmd.execute(pw, listOf()) + // THEN exec is not called, since the subcommand is required + assertThat(cmd.execCalled).isFalse() + } + + class MyCommand(private val onExecute: ((MyCommand) -> Unit)? = null) : ParseableCommand(name) { val flag1 by flag(shortName = "f", longName = "flag1", description = "flag 1 for test") val flag2 by flag(shortName = "g", longName = "flag2", description = "flag 2 for test") val singleParam: String? by - param( - shortName = "a", - longName = "arg1", - valueParser = Type.String, - ) + param(shortName = "a", longName = "arg1", valueParser = Type.String) override fun execute(pw: PrintWriter) { onExecute?.invoke(this) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt new file mode 100644 index 000000000000..14787e169979 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel + +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.chips.notification.shared.StatusBarPopupChips +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@EnableFlags(StatusBarPopupChips.FLAG_NAME) +@RunWith(AndroidJUnit4::class) +class StatusBarPopupChipsViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest = kosmos.statusBarPopupChipsViewModel + + @Test + fun popupChips_allHidden_empty() = + testScope.runTest { + val latest by collectLastValue(underTest.popupChips) + assertThat(latest).isEmpty() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt index abd0a284ae3d..3359db0a22e6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt @@ -43,7 +43,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) -class PromotedNotificationContentExtractorTest : SysuiTestCase() { +class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { private val kosmos = testKosmos() private val provider = @@ -54,7 +54,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @DisableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun shouldNotExtract_bothFlagsDisabled() { - val notif = createEntry().also { provider.promotedEntries.add(it) } + val notif = createEntry() val content = extractContent(notif) assertThat(content).isNull() } @@ -63,7 +63,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @EnableFlags(PromotedNotificationUi.FLAG_NAME) @DisableFlags(StatusBarNotifChips.FLAG_NAME) fun shouldExtract_promotedNotificationUiFlagEnabled() { - val entry = createEntry().also { provider.promotedEntries.add(it) } + val entry = createEntry() val content = extractContent(entry) assertThat(content).isNotNull() } @@ -72,7 +72,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @EnableFlags(StatusBarNotifChips.FLAG_NAME) @DisableFlags(PromotedNotificationUi.FLAG_NAME) fun shouldExtract_statusBarNotifChipsFlagEnabled() { - val entry = createEntry().also { provider.promotedEntries.add(it) } + val entry = createEntry() val content = extractContent(entry) assertThat(content).isNotNull() } @@ -80,7 +80,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun shouldExtract_bothFlagsEnabled() { - val entry = createEntry().also { provider.promotedEntries.add(it) } + val entry = createEntry() val content = extractContent(entry) assertThat(content).isNotNull() } @@ -88,22 +88,19 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun shouldNotExtract_providerDidNotPromote() { - val entry = createEntry().also { provider.promotedEntries.remove(it) } + val entry = createEntry(promoted = false) val content = extractContent(entry) assertThat(content).isNull() } @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractContent_commonFields() { - val entry = - createEntry { - setSubText(TEST_SUB_TEXT) - setContentTitle(TEST_CONTENT_TITLE) - setContentText(TEST_CONTENT_TEXT) - setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) - } - .also { provider.promotedEntries.add(it) } + fun extractsContent_commonFields() { + val entry = createEntry { + setSubText(TEST_SUB_TEXT) + setContentTitle(TEST_CONTENT_TITLE) + setContentText(TEST_CONTENT_TEXT) + } val content = extractContent(entry) @@ -117,9 +114,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) @DisableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) fun extractContent_apiFlagOff_shortCriticalTextNotExtracted() { - val entry = - createEntry { setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) } - .also { provider.promotedEntries.add(it) } + val entry = createEntry { setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) } val content = extractContent(entry) @@ -134,9 +129,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { android.app.Flags.FLAG_API_RICH_ONGOING, ) fun extractContent_apiFlagOn_shortCriticalTextExtracted() { - val entry = - createEntry { setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) } - .also { provider.promotedEntries.add(it) } + val entry = createEntry { setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) } val content = extractContent(entry) @@ -151,7 +144,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { android.app.Flags.FLAG_API_RICH_ONGOING, ) fun extractContent_noShortCriticalTextSet_textIsNull() { - val entry = createEntry {}.also { provider.promotedEntries.add(it) } + val entry = createEntry { setShortCriticalText(null) } val content = extractContent(entry) @@ -161,9 +154,8 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractContent_fromBigPictureStyle() { - val entry = - createEntry { setStyle(BigPictureStyle()) }.also { provider.promotedEntries.add(it) } + fun extractsContent_fromBigPictureStyle() { + val entry = createEntry { setStyle(BigPictureStyle()) } val content = extractContent(entry) @@ -174,8 +166,7 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun extractContent_fromBigTextStyle() { - val entry = - createEntry { setStyle(BigTextStyle()) }.also { provider.promotedEntries.add(it) } + val entry = createEntry { setStyle(BigTextStyle()) } val content = extractContent(entry) @@ -187,11 +178,13 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun extractContent_fromCallStyle() { val hangUpIntent = - PendingIntent.getBroadcast(context, 0, Intent("hangup"), PendingIntent.FLAG_IMMUTABLE) - - val entry = - createEntry { setStyle(CallStyle.forOngoingCall(TEST_PERSON, hangUpIntent)) } - .also { provider.promotedEntries.add(it) } + PendingIntent.getBroadcast( + context, + 0, + Intent("hangup_action"), + PendingIntent.FLAG_IMMUTABLE, + ) + val entry = createEntry { setStyle(CallStyle.forOngoingCall(TEST_PERSON, hangUpIntent)) } val content = extractContent(entry) @@ -202,11 +195,9 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun extractContent_fromProgressStyle() { - val entry = - createEntry { - setStyle(ProgressStyle().addProgressSegment(Segment(100)).setProgress(75)) - } - .also { provider.promotedEntries.add(it) } + val entry = createEntry { + setStyle(ProgressStyle().addProgressSegment(Segment(100)).setProgress(75)) + } val content = extractContent(entry) @@ -220,13 +211,9 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun extractContent_fromIneligibleStyle() { - val entry = - createEntry { - setStyle( - MessagingStyle(TEST_PERSON).addMessage("message text", 0L, TEST_PERSON) - ) - } - .also { provider.promotedEntries.add(it) } + val entry = createEntry { + setStyle(MessagingStyle(TEST_PERSON).addMessage("message text", 0L, TEST_PERSON)) + } val content = extractContent(entry) @@ -239,9 +226,14 @@ class PromotedNotificationContentExtractorTest : SysuiTestCase() { return underTest.extractContent(entry, recoveredBuilder) } - private fun createEntry(builderBlock: Notification.Builder.() -> Unit = {}): NotificationEntry { - val notif = Notification.Builder(context, "a").also(builderBlock).build() - return NotificationEntryBuilder().setNotification(notif).build() + private fun createEntry( + promoted: Boolean = true, + builderBlock: Notification.Builder.() -> Unit = {}, + ): NotificationEntry { + val notif = Notification.Builder(context, "channel").also(builderBlock).build() + return NotificationEntryBuilder().setNotification(notif).build().also { + provider.shouldPromoteForEntry[it] = promoted + } } companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java index 6eb2764165b5..a49a66fe26b2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java @@ -16,12 +16,18 @@ package com.android.systemui.statusbar.notification.row; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -30,14 +36,15 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; +import android.app.Person; import android.content.Context; +import android.graphics.drawable.Icon; import android.os.AsyncTask; import android.os.CancellationSignal; import android.os.Handler; @@ -61,12 +68,13 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor; +import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction; import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder; @@ -105,7 +113,8 @@ public class NotificationContentInflaterTest extends SysuiTestCase { @Mock private NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider; @Mock private HeadsUpStyleProvider mHeadsUpStyleProvider; @Mock private NotifLayoutInflaterFactory mNotifLayoutInflaterFactory; - @Mock private PromotedNotificationContentExtractor mPromotedNotificationContentExtractor; + private final FakePromotedNotificationContentExtractor mPromotedNotificationContentExtractor = + new FakePromotedNotificationContentExtractor(); private final SmartReplyStateInflater mSmartReplyStateInflater = new SmartReplyStateInflater() { @@ -155,8 +164,8 @@ public class NotificationContentInflaterTest extends SysuiTestCase { @Test public void testIncreasedHeadsUpBeingUsed() { - BindParams params = new BindParams(); - params.usesIncreasedHeadsUpHeight = true; + BindParams params = new BindParams(false, false, /* usesIncreasedHeadsUpHeight */ true, + REDACTION_TYPE_NONE); Notification.Builder builder = spy(mBuilder); mNotificationInflater.inflateNotificationViews( mRow.getEntry(), @@ -166,14 +175,15 @@ public class NotificationContentInflaterTest extends SysuiTestCase { FLAG_CONTENT_VIEW_ALL, builder, mContext, + mContext, mSmartReplyStateInflater); verify(builder).createHeadsUpContentView(true); } @Test public void testIncreasedHeightBeingUsed() { - BindParams params = new BindParams(); - params.usesIncreasedHeight = true; + BindParams params = new BindParams(false, /* usesIncreasedHeight */ true, false, + REDACTION_TYPE_NONE); Notification.Builder builder = spy(mBuilder); mNotificationInflater.inflateNotificationViews( mRow.getEntry(), @@ -183,6 +193,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { FLAG_CONTENT_VIEW_ALL, builder, mContext, + mContext, mSmartReplyStateInflater); verify(builder).createContentView(true); } @@ -207,7 +218,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { mRow.getEntry().getSbn().getNotification().contentView = new RemoteViews(mContext.getPackageName(), com.android.systemui.res.R.layout.status_bar); inflateAndWait(true /* expectingException */, mNotificationInflater, FLAG_CONTENT_VIEW_ALL, - mRow); + REDACTION_TYPE_NONE, mRow); assertTrue(mRow.getPrivateLayout().getChildCount() == 0); verify(mRow, times(0)).onNotificationUpdated(); } @@ -227,7 +238,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { mRow.getEntry(), mRow, FLAG_CONTENT_VIEW_ALL, - new BindParams(), + new BindParams(false, false, false, REDACTION_TYPE_NONE), false /* forceInflate */, null /* callback */); Assert.assertNull(mRow.getEntry().getRunningTask()); @@ -287,7 +298,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { mBuilder.setCustomContentView(new RemoteViews(getContext().getPackageName(), R.layout.custom_view_dark)); RemoteViews decoratedMediaView = mBuilder.createContentView(); - Assert.assertFalse("The decorated media style doesn't allow a view to be reapplied!", + assertFalse("The decorated media style doesn't allow a view to be reapplied!", NotificationContentInflater.canReapplyRemoteView(mediaView, decoratedMediaView)); } @@ -385,7 +396,8 @@ public class NotificationContentInflaterTest extends SysuiTestCase { mRow.getPrivateLayout().removeAllViews(); mRow.getEntry().getSbn().getNotification().contentView = new RemoteViews(mContext.getPackageName(), R.layout.invalid_notification_height); - inflateAndWait(true, mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); + inflateAndWait(true, mNotificationInflater, FLAG_CONTENT_VIEW_ALL, REDACTION_TYPE_NONE, + mRow); assertEquals(0, mRow.getPrivateLayout().getChildCount()); verify(mRow, times(0)).onNotificationUpdated(); } @@ -395,12 +407,11 @@ public class NotificationContentInflaterTest extends SysuiTestCase { public void testExtractsPromotedContent_notWhenBothFlagsDisabled() throws Exception { final PromotedNotificationContentModel content = new PromotedNotificationContentModel.Builder("key").build(); - when(mPromotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content); + mPromotedNotificationContentExtractor.resetForEntry(mRow.getEntry(), content); inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); - verify(mPromotedNotificationContentExtractor, never()).extractContent(any(), any()); + mPromotedNotificationContentExtractor.verifyZeroExtractCalls(); } @Test @@ -410,12 +421,11 @@ public class NotificationContentInflaterTest extends SysuiTestCase { throws Exception { final PromotedNotificationContentModel content = new PromotedNotificationContentModel.Builder("key").build(); - when(mPromotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content); + mPromotedNotificationContentExtractor.resetForEntry(mRow.getEntry(), content); inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); - verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any()); + mPromotedNotificationContentExtractor.verifyOneExtractCall(); assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel()); } @@ -425,12 +435,11 @@ public class NotificationContentInflaterTest extends SysuiTestCase { public void testExtractsPromotedContent_whenStatusBarNotifChipsFlagEnabled() throws Exception { final PromotedNotificationContentModel content = new PromotedNotificationContentModel.Builder("key").build(); - when(mPromotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content); + mPromotedNotificationContentExtractor.resetForEntry(mRow.getEntry(), content); inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); - verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any()); + mPromotedNotificationContentExtractor.verifyOneExtractCall(); assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel()); } @@ -439,36 +448,107 @@ public class NotificationContentInflaterTest extends SysuiTestCase { public void testExtractsPromotedContent_whenBothFlagsEnabled() throws Exception { final PromotedNotificationContentModel content = new PromotedNotificationContentModel.Builder("key").build(); - when(mPromotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content); + mPromotedNotificationContentExtractor.resetForEntry(mRow.getEntry(), content); inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); - verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any()); + mPromotedNotificationContentExtractor.verifyOneExtractCall(); assertEquals(content, mRow.getEntry().getPromotedNotificationContentModel()); } @Test @EnableFlags({PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME}) public void testExtractsPromotedContent_null() throws Exception { - when(mPromotedNotificationContentExtractor.extractContent(any(), any())).thenReturn(null); + mPromotedNotificationContentExtractor.resetForEntry(mRow.getEntry(), null); inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow); - verify(mPromotedNotificationContentExtractor, times(1)).extractContent(any(), any()); + mPromotedNotificationContentExtractor.verifyOneExtractCall(); assertNull(mRow.getEntry().getPromotedNotificationContentModel()); } + @Test + @EnableFlags(LockscreenOtpRedaction.FLAG_NAME) + public void testSensitiveContentPublicView_messageStyle() throws Exception { + String displayName = "Display Name"; + String messageText = "Message Text"; + String contentText = "Content Text"; + Icon personIcon = Icon.createWithResource(mContext, + com.android.systemui.res.R.drawable.ic_person); + Person testPerson = new Person.Builder() + .setName(displayName) + .setIcon(personIcon) + .build(); + Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(testPerson); + messagingStyle.addMessage(new Notification.MessagingStyle.Message(messageText, + System.currentTimeMillis(), testPerson)); + messagingStyle.setConversationType(Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL); + messagingStyle.setShortcutIcon(personIcon); + Notification messageNotif = new Notification.Builder(mContext).setSmallIcon( + com.android.systemui.res.R.drawable.ic_person).setStyle(messagingStyle).build(); + ExpandableNotificationRow row = mHelper.createRow(messageNotif); + inflateAndWait(false, mNotificationInflater, FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_SENSITIVE_CONTENT, row); + NotificationContentView publicView = row.getPublicLayout(); + assertNotNull(publicView); + // The display name should be included, but not the content or message text + assertFalse(hasText(publicView, messageText)); + assertFalse(hasText(publicView, contentText)); + assertTrue(hasText(publicView, displayName)); + } + + @Test + @EnableFlags(LockscreenOtpRedaction.FLAG_NAME) + public void testSensitiveContentPublicView_nonMessageStyle() throws Exception { + String contentTitle = "Content Title"; + String contentText = "Content Text"; + Notification notif = new Notification.Builder(mContext).setSmallIcon( + com.android.systemui.res.R.drawable.ic_person) + .setContentTitle(contentTitle) + .setContentText(contentText) + .build(); + ExpandableNotificationRow row = mHelper.createRow(notif); + inflateAndWait(false, mNotificationInflater, FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_SENSITIVE_CONTENT, row); + NotificationContentView publicView = row.getPublicLayout(); + assertNotNull(publicView); + assertFalse(hasText(publicView, contentText)); + assertTrue(hasText(publicView, contentTitle)); + + // The standard public view should not use the content title or text + inflateAndWait(false, mNotificationInflater, FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_PUBLIC, row); + publicView = row.getPublicLayout(); + assertFalse(hasText(publicView, contentText)); + assertFalse(hasText(publicView, contentTitle)); + } + + private static boolean hasText(ViewGroup parent, CharSequence text) { + for (int i = 0; i < parent.getChildCount(); i++) { + View child = parent.getChildAt(i); + if (child instanceof ViewGroup) { + if (hasText((ViewGroup) child, text)) { + return true; + } + } else if (child instanceof TextView) { + return ((TextView) child).getText().toString().contains(text); + } + } + return false; + } + private static void inflateAndWait(NotificationContentInflater inflater, @InflationFlag int contentToInflate, ExpandableNotificationRow row) throws Exception { - inflateAndWait(false /* expectingException */, inflater, contentToInflate, row); + inflateAndWait(false /* expectingException */, inflater, contentToInflate, + REDACTION_TYPE_NONE, row); } private static void inflateAndWait(boolean expectingException, NotificationContentInflater inflater, @InflationFlag int contentToInflate, + @RedactionType int redactionType, ExpandableNotificationRow row) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(1); final ExceptionHolder exceptionHolder = new ExceptionHolder(); @@ -496,7 +576,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { row.getEntry(), row, contentToInflate, - new BindParams(), + new BindParams(false, false, false, redactionType), false /* forceInflate */, callback /* callback */); assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt index 18517998096a..f25ba2c93c65 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row import android.app.Notification import android.app.Person import android.content.Context +import android.graphics.drawable.Icon import android.os.AsyncTask import android.os.Build import android.os.CancellationSignal @@ -34,10 +35,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.res.R +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT +import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor +import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams @@ -45,6 +50,7 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag @@ -67,7 +73,6 @@ import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock -import org.mockito.kotlin.never import org.mockito.kotlin.spy import org.mockito.kotlin.times import org.mockito.kotlin.verify @@ -110,7 +115,8 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { return inflatedSmartReplyState } } - private val promotedNotificationContentExtractor: PromotedNotificationContentExtractor = mock() + private val promotedNotificationContentExtractor = FakePromotedNotificationContentExtractor() + private val conversationNotificationProcessor: ConversationNotificationProcessor = mock() @Before fun setUp() { @@ -127,7 +133,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { NotificationRowContentBinderImpl( cache, mock(), - mock<ConversationNotificationProcessor>(), + conversationNotificationProcessor, mock(), smartReplyStateInflater, layoutInflaterFactoryProvider, @@ -139,14 +145,14 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun testIncreasedHeadsUpBeingUsed() { - val params = BindParams() - params.usesIncreasedHeadsUpHeight = true + val params = + BindParams(false, false, /* usesIncreasedHeadsUpHeight */ true, REDACTION_TYPE_NONE) val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, - true /* inflateSynchronously */, + true, /* inflateSynchronously */ FLAG_CONTENT_VIEW_ALL, builder, mContext, @@ -158,14 +164,13 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun testIncreasedHeightBeingUsed() { - val params = BindParams() - params.usesIncreasedHeight = true + val params = BindParams(false, /* usesIncreasedHeight */ true, false, REDACTION_TYPE_NONE) val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, - true /* inflateSynchronously */, + true, /* inflateSynchronously */ FLAG_CONTENT_VIEW_ALL, builder, mContext, @@ -194,15 +199,18 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { row.entry.sbn.notification.contentView = RemoteViews(mContext.packageName, R.layout.status_bar) inflateAndWait( - true /* expectingException */, + true, /* expectingException */ notificationInflater, FLAG_CONTENT_VIEW_ALL, + REDACTION_TYPE_NONE, row, ) Assert.assertTrue(row.privateLayout.childCount == 0) verify(row, times(0)).onNotificationUpdated() } + @Test fun testInflationOfSensitiveContentPublicView() {} + @Test fun testAsyncTaskRemoved() { row.entry.abortTask() @@ -218,8 +226,8 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { row.entry, row, FLAG_CONTENT_VIEW_ALL, - BindParams(), - false /* forceInflate */, + BindParams(false, false, false, REDACTION_TYPE_NONE), + false, /* forceInflate */ null, /* callback */ ) Assert.assertNull(row.entry.runningTask) @@ -234,7 +242,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { packageContext = mContext, remoteViews = NewRemoteViews(), contentModel = NotificationContentModel(headsUpStatusBarModel), - extractedPromotedNotificationContentModel = null, + promotedContent = null, ) val countDownLatch = CountDownLatch(1) NotificationRowContentBinderImpl.applyRemoteView( @@ -432,7 +440,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { mContext.packageName, com.android.systemui.tests.R.layout.invalid_notification_height, ) - inflateAndWait(true, notificationInflater, FLAG_CONTENT_VIEW_ALL, row) + inflateAndWait(true, notificationInflater, FLAG_CONTENT_VIEW_ALL, REDACTION_TYPE_NONE, row) Assert.assertEquals(0, row.privateLayout.childCount.toLong()) verify(row, times(0)).onNotificationUpdated() } @@ -441,7 +449,13 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun testInflatePublicSingleLineView() { row.publicLayout.removeAllViews() - inflateAndWait(false, notificationInflater, FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, row) + inflateAndWait( + false, + notificationInflater, + FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, + REDACTION_TYPE_NONE, + row, + ) Assert.assertNotNull(row.publicLayout.mSingleLineView) Assert.assertTrue(row.publicLayout.mSingleLineView is HybridNotificationView) } @@ -449,12 +463,15 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun testInflatePublicSingleLineConversationView() { val testPerson = Person.Builder().setName("Person").build() + val style = Notification.MessagingStyle(testPerson) val messagingBuilder = Notification.Builder(mContext, "no-id") .setSmallIcon(R.drawable.ic_person) .setContentTitle("Title") .setContentText("Text") - .setStyle(Notification.MessagingStyle(testPerson)) + .setStyle(style) + whenever(conversationNotificationProcessor.processNotification(any(), any(), any())) + .thenReturn(style) val messagingRow = spy(testHelper.createRow(messagingBuilder.build())) messagingRow.publicLayout.removeAllViews() @@ -462,6 +479,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { false, notificationInflater, FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE, + REDACTION_TYPE_NONE, messagingRow, ) Assert.assertNotNull(messagingRow.publicLayout.mSingleLineView) @@ -475,12 +493,11 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @DisableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun testExtractsPromotedContent_notWhenBothFlagsDisabled() { val content = PromotedNotificationContentModel.Builder("key").build() - whenever(promotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content) + promotedNotificationContentExtractor.resetForEntry(row.entry, content) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) - verify(promotedNotificationContentExtractor, never()).extractContent(any(), any()) + promotedNotificationContentExtractor.verifyZeroExtractCalls() } @Test @@ -488,12 +505,11 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @DisableFlags(StatusBarNotifChips.FLAG_NAME) fun testExtractsPromotedContent_whenPromotedNotificationUiFlagEnabled() { val content = PromotedNotificationContentModel.Builder("key").build() - whenever(promotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content) + promotedNotificationContentExtractor.resetForEntry(row.entry, content) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) - verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any()) + promotedNotificationContentExtractor.verifyOneExtractCall() Assert.assertEquals(content, row.entry.promotedNotificationContentModel) } @@ -502,12 +518,11 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @DisableFlags(PromotedNotificationUi.FLAG_NAME) fun testExtractsPromotedContent_whenStatusBarNotifChipsFlagEnabled() { val content = PromotedNotificationContentModel.Builder("key").build() - whenever(promotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content) + promotedNotificationContentExtractor.resetForEntry(row.entry, content) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) - verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any()) + promotedNotificationContentExtractor.verifyOneExtractCall() Assert.assertEquals(content, row.entry.promotedNotificationContentModel) } @@ -515,15 +530,99 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun testExtractsPromotedContent_whenBothFlagsEnabled() { val content = PromotedNotificationContentModel.Builder("key").build() - whenever(promotedNotificationContentExtractor.extractContent(any(), any())) - .thenReturn(content) + promotedNotificationContentExtractor.resetForEntry(row.entry, content) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) - verify(promotedNotificationContentExtractor, times(1)).extractContent(any(), any()) + promotedNotificationContentExtractor.verifyOneExtractCall() Assert.assertEquals(content, row.entry.promotedNotificationContentModel) } + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun testExtractsPromotedContent_null() { + promotedNotificationContentExtractor.resetForEntry(row.entry, null) + + inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) + + promotedNotificationContentExtractor.verifyOneExtractCall() + Assert.assertNull(row.entry.promotedNotificationContentModel) + } + + @Test + @Throws(java.lang.Exception::class) + @EnableFlags(LockscreenOtpRedaction.FLAG_NAME) + fun testSensitiveContentPublicView_messageStyle() { + val displayName = "Display Name" + val messageText = "Message Text" + val contentText = "Content Text" + val personIcon = Icon.createWithResource(mContext, R.drawable.ic_person) + val testPerson = Person.Builder().setName(displayName).setIcon(personIcon).build() + val messagingStyle = Notification.MessagingStyle(testPerson) + messagingStyle.addMessage( + Notification.MessagingStyle.Message(messageText, System.currentTimeMillis(), testPerson) + ) + messagingStyle.setConversationType(Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL) + messagingStyle.setShortcutIcon(personIcon) + val messageNotif = + Notification.Builder(mContext) + .setSmallIcon(R.drawable.ic_person) + .setStyle(messagingStyle) + .build() + val newRow: ExpandableNotificationRow = testHelper.createRow(messageNotif) + inflateAndWait( + false, + notificationInflater, + FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_SENSITIVE_CONTENT, + newRow, + ) + // The display name should be included, but not the content or message text + val publicView = newRow.publicLayout + Assert.assertNotNull(publicView) + Assert.assertFalse(hasText(publicView, messageText)) + Assert.assertFalse(hasText(publicView, contentText)) + Assert.assertTrue(hasText(publicView, displayName)) + } + + @Test + @Throws(java.lang.Exception::class) + @EnableFlags(LockscreenOtpRedaction.FLAG_NAME) + fun testSensitiveContentPublicView_nonMessageStyle() { + val contentTitle = "Content Title" + val contentText = "Content Text" + val notif = + Notification.Builder(mContext) + .setSmallIcon(R.drawable.ic_person) + .setContentTitle(contentTitle) + .setContentText(contentText) + .build() + val newRow: ExpandableNotificationRow = testHelper.createRow(notif) + inflateAndWait( + false, + notificationInflater, + FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_SENSITIVE_CONTENT, + newRow, + ) + var publicView = newRow.publicLayout + Assert.assertNotNull(publicView) + Assert.assertFalse(hasText(publicView, contentText)) + Assert.assertTrue(hasText(publicView, contentTitle)) + + // The standard public view should not use the content title or text + inflateAndWait( + false, + notificationInflater, + FLAG_CONTENT_VIEW_PUBLIC, + REDACTION_TYPE_PUBLIC, + newRow, + ) + publicView = newRow.publicLayout + Assert.assertFalse(hasText(publicView, contentText)) + Assert.assertFalse(hasText(publicView, contentTitle)) + } + private class ExceptionHolder { var exception: Exception? = null } @@ -562,13 +661,20 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @InflationFlag contentToInflate: Int, row: ExpandableNotificationRow, ) { - inflateAndWait(false /* expectingException */, inflater, contentToInflate, row) + inflateAndWait( + false /* expectingException */, + inflater, + contentToInflate, + REDACTION_TYPE_NONE, + row, + ) } private fun inflateAndWait( expectingException: Boolean, inflater: NotificationRowContentBinderImpl, @InflationFlag contentToInflate: Int, + @RedactionType redactionType: Int, row: ExpandableNotificationRow, ) { val countDownLatch = CountDownLatch(1) @@ -597,12 +703,26 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { row.entry, row, contentToInflate, - BindParams(), - false /* forceInflate */, + BindParams(false, false, false, redactionType), + false, /* forceInflate */ callback, /* callback */ ) Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)) exceptionHolder.exception?.let { throw it } } + + fun hasText(parent: ViewGroup, text: CharSequence): Boolean { + for (i in 0 until parent.childCount) { + val child = parent.getChildAt(i) + if (child is ViewGroup) { + if (hasText(child, text)) { + return true + } + } else if (child is TextView) { + return child.text.toString().contains(text) + } + } + return false + } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index b323ef85b370..b8d18757afbb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -81,7 +81,7 @@ import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.icon.IconBuilder; import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor; +import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; @@ -201,7 +201,7 @@ public class NotificationTestHelper { new MockSmartReplyInflater(), mock(NotifLayoutInflaterFactory.Provider.class), mock(HeadsUpStyleProvider.class), - mock(PromotedNotificationContentExtractor.class), + new FakePromotedNotificationContentExtractor(), mock(NotificationRowContentBinderLogger.class)) : new NotificationContentInflater( mock(NotifRemoteViewCache.class), @@ -212,7 +212,7 @@ public class NotificationTestHelper { new MockSmartReplyInflater(), mock(NotifLayoutInflaterFactory.Provider.class), mock(HeadsUpStyleProvider.class), - mock(PromotedNotificationContentExtractor.class), + new FakePromotedNotificationContentExtractor(), mock(NotificationRowContentBinderLogger.class)); contentBinder.setInflateSynchronously(true); mBindStage = new RowContentBindStage(contentBinder, 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 de40abb4d9d8..c6cffa9da13b 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 @@ -952,11 +952,10 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Test @EnableSceneContainer public void onTouchEvent_stopExpandingNotification_sceneContainerEnabled() { - boolean touchHandled = stopExpandingNotification(); + stopExpandingNotification(); - verify(mNotificationStackScrollLayout).startOverscrollAfterExpanding(); + verify(mExpandHelper).finishExpanding(); verify(mNotificationStackScrollLayout, never()).dispatchDownEventToScroller(any()); - assertTrue(touchHandled); } @Test @@ -964,11 +963,11 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { public void onTouchEvent_stopExpandingNotification_sceneContainerDisabled() { stopExpandingNotification(); - verify(mNotificationStackScrollLayout, never()).startOverscrollAfterExpanding(); + verify(mExpandHelper, never()).finishExpanding(); verify(mNotificationStackScrollLayout).dispatchDownEventToScroller(any()); } - private boolean stopExpandingNotification() { + private void stopExpandingNotification() { when(mNotificationStackScrollLayout.getExpandHelper()).thenReturn(mExpandHelper); when(mNotificationStackScrollLayout.getIsExpanded()).thenReturn(true); when(mNotificationStackScrollLayout.getExpandedInThisMotion()).thenReturn(true); @@ -983,13 +982,13 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { NotificationStackScrollLayoutController.TouchHandler touchHandler = mController.getTouchHandler(); - return touchHandler.onTouchEvent(MotionEvent.obtain( - /* downTime= */ 0, - /* eventTime= */ 0, - MotionEvent.ACTION_DOWN, - 0, - 0, - /* metaState= */ 0 + touchHandler.onTouchEvent(MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 0, + MotionEvent.ACTION_DOWN, + 0, + 0, + /* metaState= */ 0 )); } 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 f48fd3c998b1..6bdd86efa8c0 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 @@ -241,7 +241,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S shadeTestUtil.setSplitShade(true) val horizontalPosition = checkNotNull(dimens).horizontalPosition - assertIs<HorizontalPosition.FloatAtEnd>(horizontalPosition) + assertIs<HorizontalPosition.FloatAtStart>(horizontalPosition) assertThat(horizontalPosition.width).isEqualTo(200) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt index c3c5a48dc197..b0b80a9419e2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt @@ -18,9 +18,14 @@ package com.android.systemui.statusbar.phone import android.app.PendingIntent import android.content.Intent +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 +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.shared.Flags as SharedFlags import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock @@ -32,6 +37,9 @@ import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.never @SmallTest @RunWith(AndroidJUnit4::class) @@ -54,6 +62,62 @@ class ActivityStarterImplTest : SysuiTestCase() { ) } + @EnableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @EnableSceneContainer + @Test + fun registerTransition_forwardsTheRequest() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java) + + underTest.registerTransition(cookie, controllerFactory) + + verify(activityStarterInternal).registerTransition(eq(cookie), eq(controllerFactory)) + } + + @DisableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun registerTransition_doesNotForwardTheRequest_whenFlaggedOff() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java) + + underTest.registerTransition(cookie, controllerFactory) + + verify(activityStarterInternal, never()).registerTransition(any(), any()) + } + + @EnableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @EnableSceneContainer + @Test + fun unregisterTransition_forwardsTheRequest() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + + underTest.unregisterTransition(cookie) + + verify(activityStarterInternal).unregisterTransition(eq(cookie)) + } + + @DisableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun unregisterTransition_doesNotForwardTheRequest_whenFlaggedOff() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + + underTest.unregisterTransition(cookie) + + verify(activityStarterInternal, never()).unregisterTransition(any()) + } + @Test fun postStartActivityDismissingKeyguard_pendingIntent_postsOnMain() { val intent = mock(PendingIntent::class.java) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt index bac79a9cc520..5406acf694ff 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt @@ -48,6 +48,7 @@ import com.android.systemui.shade.ShadeController import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.ShadeAnimationRepository import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl +import com.android.systemui.shared.Flags as SharedFlags import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.NotificationShadeWindowController @@ -63,6 +64,7 @@ import com.google.common.truth.Truth.assertThat import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -149,6 +151,63 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(false)) } + @EnableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun registerTransition_registers() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java) + `when`(controllerFactory.cookie).thenReturn(cookie) + + underTest.registerTransition(cookie, controllerFactory) + + verify(activityTransitionAnimator).register(eq(cookie), any()) + } + + @DisableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun registerTransition_throws_whenFlagsAreDisabled() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + val controllerFactory = mock(ActivityTransitionAnimator.ControllerFactory::class.java) + + assertThrows(IllegalStateException::class.java) { + underTest.registerTransition(cookie, controllerFactory) + } + + verify(activityTransitionAnimator, never()).register(any(), any()) + } + + @EnableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun unregisterTransition_unregisters() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + + underTest.unregisterTransition(cookie) + + verify(activityTransitionAnimator).unregister(eq(cookie)) + } + + @DisableFlags( + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + SharedFlags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun unregisterTransition_throws_whenFlagsAreDisabled() { + val cookie = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + + assertThrows(IllegalStateException::class.java) { underTest.unregisterTransition(cookie) } + + verify(activityTransitionAnimator, never()).unregister(eq(cookie)) + } + @Test fun startActivityDismissingKeyguard_dismissShadeWhenOccluded_runAfterKeyguardGone() { val intent = mock(Intent::class.java) @@ -216,7 +275,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { underTest.startPendingIntentDismissingKeyguard( intent = pendingIntent, dismissShade = true, - customMessage = customMessage + customMessage = customMessage, ) mainExecutor.runAllReady() @@ -296,7 +355,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { nullable(PendingIntent.OnFinished::class.java), nullable(Handler::class.java), nullable(String::class.java), - bundleCaptor.capture() + bundleCaptor.capture(), ) val options = ActivityOptions.fromBundle(bundleCaptor.firstValue) assertThat(options.getPendingIntentBackgroundActivityStartMode()) @@ -339,7 +398,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { dismissShade = true, animationController = controller, showOverLockscreen = true, - skipLockscreenChecks = true + skipLockscreenChecks = true, ) mainExecutor.runAllReady() @@ -373,7 +432,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { dismissShade = true, animationController = controller, showOverLockscreen = true, - skipLockscreenChecks = true + skipLockscreenChecks = true, ) mainExecutor.runAllReady() @@ -413,7 +472,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { dismissShade = false, animationController = controller, showOverLockscreen = true, - skipLockscreenChecks = false + skipLockscreenChecks = false, ) mainExecutor.runAllReady() @@ -458,7 +517,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { dismissShade = false, animationController = controller, showOverLockscreen = true, - skipLockscreenChecks = false + skipLockscreenChecks = false, ) mainExecutor.runAllReady() @@ -583,7 +642,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { }, {}, false, - customMessage + customMessage, ) verify(centralSurfaces).awakenDreams() @@ -602,7 +661,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { cancelAction = null, dismissShade = false, afterKeyguardGone = false, - deferred = false + deferred = false, ) verify(centralSurfaces, times(1)).awakenDreams() @@ -620,7 +679,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() { cancelAction = null, dismissShade = false, afterKeyguardGone = false, - deferred = false + deferred = false, ) verify(centralSurfaces, never()).awakenDreams() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt index c347347eff83..baea1a1d2dca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import android.app.Notification import android.app.Notification.Builder +import android.app.PendingIntent import android.app.StatusBarManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags @@ -36,11 +37,11 @@ import com.android.systemui.kosmos.runTest import com.android.systemui.plugins.activityStarter import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.settings.FakeDisplayTracker -import com.android.systemui.shade.NotificationShadeWindowView -import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.domain.interactor.panelExpansionInteractor +import com.android.systemui.shade.notificationShadeWindowView import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.commandQueue import com.android.systemui.statusbar.lockscreenShadeTransitionController import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder @@ -79,40 +80,34 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @RunWithLooper class StatusBarNotificationPresenterTest : SysuiTestCase() { - private lateinit var kosmos: Kosmos + private val kosmos: Kosmos = + testKosmos().apply { + whenever(notificationShadeWindowView.resources).thenReturn(mContext.resources) + whenever(notificationStackScrollLayoutController.view).thenReturn(mock()) + whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(true) + commandQueue = CommandQueue(mContext, FakeDisplayTracker(mContext)) + + // override this controller with a mock, otherwise it would start some animators which + // are not cleaned up after these tests + lockscreenShadeTransitionController = mock() + } + // initiated by argumentCaptors later in the setup step, based on the flag states private var interruptSuppressor: NotificationInterruptSuppressor? = null private var alertsDisabledCondition: VisualInterruptionCondition? = null private var vrModeCondition: VisualInterruptionCondition? = null private var needsRedactionFilter: VisualInterruptionFilter? = null private var panelsDisabledCondition: VisualInterruptionCondition? = null - private val commandQueue: CommandQueue = CommandQueue(mContext, FakeDisplayTracker(mContext)) - private val keyguardStateController: KeyguardStateController - get() = kosmos.keyguardStateController - - private val notificationAlertsInteractor - get() = kosmos.notificationAlertsInteractor - - private val visualInterruptionDecisionProvider - get() = kosmos.visualInterruptionDecisionProvider + private val commandQueue: CommandQueue = kosmos.commandQueue + private val keyguardStateController: KeyguardStateController = kosmos.keyguardStateController + private val notificationAlertsInteractor = kosmos.notificationAlertsInteractor + private val visualInterruptionDecisionProvider = kosmos.visualInterruptionDecisionProvider private lateinit var underTest: StatusBarNotificationPresenter @Before fun setup() { - kosmos = - testKosmos().apply { - whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()) - .thenReturn(true) - whenever(notificationStackScrollLayoutController.expandHelperCallback) - .thenReturn(mock()) - lockscreenShadeTransitionController.setStackScroller( - notificationStackScrollLayoutController - ) - lockscreenShadeTransitionController.centralSurfaces = mock() - } - underTest = createPresenter() if (VisualInterruptionRefactor.isEnabled) { verifyAndCaptureSuppressors() @@ -162,13 +157,12 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressHeadsUp_disabledStatusBar_refactorDisabled() { commandQueue.disable( - DEFAULT_DISPLAY, - StatusBarManager.DISABLE_EXPAND, - 0, - false, /* animate */ + /* displayId = */ DEFAULT_DISPLAY, + /* flags = */ StatusBarManager.DISABLE_EXPAND, + /* reason = */ 0, + /* animate = */ false, ) TestableLooper.get(this).processAllMessages() - assertWithMessage("The panel should suppress heads up while disabled") .that(interruptSuppressor!!.suppressAwakeHeadsUp(createNotificationEntry())) .isTrue() @@ -178,13 +172,12 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressHeadsUp_disabledStatusBar_refactorEnabled() { commandQueue.disable( - DEFAULT_DISPLAY, - StatusBarManager.DISABLE_EXPAND, - 0, - false, /* animate */ + /* displayId = */ DEFAULT_DISPLAY, + /* flags = */ StatusBarManager.DISABLE_EXPAND, + /* reason = */ 0, + /* animate = */ false, ) TestableLooper.get(this).processAllMessages() - assertWithMessage("The panel should suppress heads up while disabled") .that(panelsDisabledCondition!!.shouldSuppress()) .isTrue() @@ -194,13 +187,12 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressHeadsUp_disabledNotificationShade_refactorDisabled() { commandQueue.disable( - DEFAULT_DISPLAY, - 0, - StatusBarManager.DISABLE2_NOTIFICATION_SHADE, - false, /* animate */ + /* displayId = */ DEFAULT_DISPLAY, + /* flags = */ 0, + /* reason = */ StatusBarManager.DISABLE2_NOTIFICATION_SHADE, + /* animate = */ false, ) TestableLooper.get(this).processAllMessages() - assertWithMessage( "The panel should suppress interruptions while notification shade disabled" ) @@ -212,13 +204,12 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressHeadsUp_disabledNotificationShade_refactorEnabled() { commandQueue.disable( - DEFAULT_DISPLAY, - 0, - StatusBarManager.DISABLE2_NOTIFICATION_SHADE, - false, /* animate */ + /* displayId = */ DEFAULT_DISPLAY, + /* flags = */ 0, + /* reason = */ StatusBarManager.DISABLE2_NOTIFICATION_SHADE, + /* animate = */ false, ) TestableLooper.get(this).processAllMessages() - assertWithMessage( "The panel should suppress interruptions while notification shade disabled" ) @@ -240,7 +231,6 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { fun testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorDisabled() { whenever(keyguardStateController.isShowing()).thenReturn(true) whenever(keyguardStateController.isOccluded()).thenReturn(false) - assertThat(interruptSuppressor!!.suppressAwakeHeadsUp(createFsiNotificationEntry())) .isFalse() } @@ -250,9 +240,7 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { fun testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorEnabled() { whenever(keyguardStateController.isShowing()).thenReturn(true) whenever(keyguardStateController.isOccluded()).thenReturn(false) - assertThat(needsRedactionFilter!!.shouldSuppress(createFsiNotificationEntry())).isFalse() - val types: Set<VisualInterruptionType> = needsRedactionFilter!!.types assertThat(types).contains(VisualInterruptionType.PEEK) assertThat(types) @@ -263,7 +251,6 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressInterruptions_vrMode_refactorDisabled() { underTest.mVrMode = true - assertWithMessage("Vr mode should suppress interruptions") .that(interruptSuppressor!!.suppressAwakeInterruptions(createNotificationEntry())) .isTrue() @@ -273,11 +260,9 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressInterruptions_vrMode_refactorEnabled() { underTest.mVrMode = true - assertWithMessage("Vr mode should suppress interruptions") .that(vrModeCondition!!.shouldSuppress()) .isTrue() - val types: Set<VisualInterruptionType> = vrModeCondition!!.types assertThat(types).contains(VisualInterruptionType.PEEK) assertThat(types).doesNotContain(VisualInterruptionType.PULSE) @@ -288,7 +273,6 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressInterruptions_statusBarAlertsDisabled_refactorDisabled() { whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false) - assertWithMessage("When alerts aren't enabled, interruptions are suppressed") .that(interruptSuppressor!!.suppressInterruptions(createNotificationEntry())) .isTrue() @@ -298,11 +282,9 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) fun testSuppressInterruptions_statusBarAlertsDisabled_refactorEnabled() { whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false) - assertWithMessage("When alerts aren't enabled, interruptions are suppressed") .that(alertsDisabledCondition!!.shouldSuppress()) .isTrue() - val types: Set<VisualInterruptionType> = alertsDisabledCondition!!.types assertThat(types).contains(VisualInterruptionType.PEEK) assertThat(types).contains(VisualInterruptionType.PULSE) @@ -321,15 +303,16 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { ) // When the user expands a sensitive Notification + val row = createRow() val entry = - createRow().entry.apply { - setSensitive(/* sensitive= */ true, /* deviceSensitive= */ true) - } + row.entry.apply { setSensitive(/* sensitive= */ true, /* deviceSensitive= */ true) } + underTest.onExpandClicked(entry, mock(), /* nowExpanded= */ true) // Then we open the locked shade - assertThat(kosmos.sysuiStatusBarStateController.state) - .isEqualTo(StatusBarState.SHADE_LOCKED) + verify(kosmos.lockscreenShadeTransitionController) + // Explicit parameters to avoid issues with Kotlin default arguments in Mockito + .goToLockedShade(row, true) } @Test @@ -352,27 +335,17 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { // Then we show the bouncer verify(kosmos.activityStarter).dismissKeyguardThenExecute(any(), eq(null), eq(false)) - // AND we are still on the locked shade - assertThat(kosmos.sysuiStatusBarStateController.state) - .isEqualTo(StatusBarState.SHADE_LOCKED) } private fun createPresenter(): StatusBarNotificationPresenter { - val shadeViewController: ShadeViewController = mock() - - val notificationShadeWindowView: NotificationShadeWindowView = mock() - whenever(notificationShadeWindowView.resources).thenReturn(mContext.resources) - whenever(kosmos.notificationStackScrollLayoutController.view).thenReturn(mock()) - val initController: InitController = InitController() - return StatusBarNotificationPresenter( - mContext, - shadeViewController, + /* context = */ mContext, + /* panel = */ mock(), kosmos.panelExpansionInteractor, /* quickSettingsController = */ mock(), kosmos.headsUpManager, - notificationShadeWindowView, + kosmos.notificationShadeWindowView, kosmos.activityStarter, kosmos.notificationStackScrollLayoutController, kosmos.dozeScrimController, @@ -382,13 +355,13 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { kosmos.notificationAlertsInteractor, kosmos.lockscreenShadeTransitionController, kosmos.powerInteractor, - commandQueue, + kosmos.commandQueue, kosmos.notificationLockscreenUserManager, kosmos.sysuiStatusBarStateController, /* notifShadeEventSource = */ mock(), /* notificationMediaManager = */ mock(), /* notificationGutsManager = */ mock(), - initController, + /* initController = */ initController, kosmos.visualInterruptionDecisionProvider, kosmos.notificationRemoteInputManager, /* remoteInputManagerCallback = */ mock(), @@ -403,6 +376,7 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { val conditionCaptor = argumentCaptor<VisualInterruptionCondition>() verify(visualInterruptionDecisionProvider, times(3)).addCondition(conditionCaptor.capture()) + val conditions: List<VisualInterruptionCondition> = conditionCaptor.allValues alertsDisabledCondition = conditions[0] vrModeCondition = conditions[1] @@ -442,8 +416,9 @@ class StatusBarNotificationPresenterTest : SysuiTestCase() { private fun createFsiNotificationEntry(): NotificationEntry { val notification: Notification = - Builder(mContext, "a").setFullScreenIntent(mock(), true).build() - + Builder(mContext, "a") + .setFullScreenIntent(mock<PendingIntent>(), /* highPriority= */ true) + .build() return NotificationEntryBuilder() .setPkg("a") .setOpPkg("a") diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt index b560c591af1e..1ee8005fb7ab 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt @@ -20,7 +20,9 @@ import android.view.WindowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any @@ -31,7 +33,6 @@ import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.runner.RunWith @@ -43,7 +44,7 @@ import org.mockito.Mockito.verify @RunWithLooper(setAsMainLooper = true) class SystemUIBottomSheetDialogTest : SysuiTestCase() { - private val kosmos = testKosmos() + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val configurationController = mock<ConfigurationController>() private val config = mock<Configuration>() private val delegate = mock<DialogDelegate<Dialog>>() @@ -67,21 +68,17 @@ class SystemUIBottomSheetDialogTest : SysuiTestCase() { @Test fun onStart_registersConfigCallback() { - kosmos.testScope.runTest { + kosmos.runTest { dialog.show() - runCurrent() - verify(configurationController).addCallback(any()) } } @Test fun onStop_unregisterConfigCallback() { - kosmos.testScope.runTest { + kosmos.runTest { dialog.show() - runCurrent() dialog.dismiss() - runCurrent() verify(configurationController).removeCallback(any()) } @@ -89,14 +86,12 @@ class SystemUIBottomSheetDialogTest : SysuiTestCase() { @Test fun onConfigurationChanged_calledInDelegate() { - kosmos.testScope.runTest { + kosmos.runTest { dialog.show() - runCurrent() val captor = argumentCaptor<ConfigurationController.ConfigurationListener>() verify(configurationController).addCallback(capture(captor)) captor.value.onConfigChanged(config) - runCurrent() verify(delegate).onConfigurationChanged(any(), any()) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 5a77f3d40e82..6efb9c77c131 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -885,6 +885,20 @@ class MobileIconsInteractorTest : SysuiTestCase() { assertThat(latest).isFalse() } + @Test + fun defaultDataSubId_tracksRepo() = + kosmos.runTest { + val latest by collectLastValue(underTest.defaultDataSubId) + + connectionsRepository.defaultDataSubId.value = 1 + + assertThat(latest).isEqualTo(1) + + connectionsRepository.defaultDataSubId.value = 2 + + assertThat(latest).isEqualTo(2) + } + /** * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions * flow. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt deleted file mode 100644 index db24d4bc8070..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt +++ /dev/null @@ -1,97 +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.statusbar.pipeline.shared.domain.interactor - -import android.app.StatusBarManager.DISABLE2_NONE -import android.app.StatusBarManager.DISABLE_CLOCK -import android.app.StatusBarManager.DISABLE_NONE -import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS -import android.app.StatusBarManager.DISABLE_SYSTEM_INFO -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.kosmos.testScope -import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository -import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlin.test.Test -import kotlinx.coroutines.test.runTest -import org.junit.runner.RunWith - -@SmallTest -@RunWith(AndroidJUnit4::class) -class CollapsedStatusBarInteractorTest : SysuiTestCase() { - val kosmos = testKosmos() - val testScope = kosmos.testScope - val disableFlagsRepo = kosmos.fakeDisableFlagsRepository - - val underTest = kosmos.collapsedStatusBarInteractor - - @Test - fun visibilityViaDisableFlags_allDisabled() = - testScope.runTest { - val latest by collectLastValue(underTest.visibilityViaDisableFlags) - - disableFlagsRepo.disableFlags.value = - DisableFlagsModel( - DISABLE_CLOCK or DISABLE_NOTIFICATION_ICONS or DISABLE_SYSTEM_INFO, - DISABLE2_NONE, - animate = false, - ) - - assertThat(latest!!.isClockAllowed).isFalse() - assertThat(latest!!.areNotificationIconsAllowed).isFalse() - assertThat(latest!!.isSystemInfoAllowed).isFalse() - } - - @Test - fun visibilityViaDisableFlags_allEnabled() = - testScope.runTest { - val latest by collectLastValue(underTest.visibilityViaDisableFlags) - - disableFlagsRepo.disableFlags.value = - DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false) - - assertThat(latest!!.isClockAllowed).isTrue() - assertThat(latest!!.areNotificationIconsAllowed).isTrue() - assertThat(latest!!.isSystemInfoAllowed).isTrue() - } - - @Test - fun visibilityViaDisableFlags_animateFalse() = - testScope.runTest { - val latest by collectLastValue(underTest.visibilityViaDisableFlags) - - disableFlagsRepo.disableFlags.value = - DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false) - - assertThat(latest!!.animate).isFalse() - } - - @Test - fun visibilityViaDisableFlags_animateTrue() = - testScope.runTest { - val latest by collectLastValue(underTest.visibilityViaDisableFlags) - - disableFlagsRepo.disableFlags.value = - DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = true) - - assertThat(latest!!.animate).isTrue() - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorTest.kt new file mode 100644 index 000000000000..523d17a85e9e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorTest.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.domain.interactor + +import android.provider.Settings +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.res.R +import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HomeStatusBarIconBlockListInteractorTest : SysuiTestCase() { + val kosmos = testKosmos() + private val Kosmos.underTest by Kosmos.Fixture { kosmos.homeStatusBarIconBlockListInteractor } + + @Test + fun iconBlockList_containsResources() = + kosmos.runTest { + // GIVEN a list of blocked icons + overrideResource( + R.array.config_collapsed_statusbar_icon_blocklist, + arrayOf("test1", "test2"), + ) + + // GIVEN the vibrate is set to show (not blocked) + fakeSecureSettingsRepository.setInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 1) + + val latest by collectLastValue(underTest.iconBlockList) + + // THEN the volume is not the blocklist + assertThat(latest).containsExactly("test1", "test2") + } + + @Test + fun iconBlockList_checksVolumeSetting() = + kosmos.runTest { + // GIVEN a list of blocked icons + overrideResource( + R.array.config_collapsed_statusbar_icon_blocklist, + arrayOf("test1", "test2"), + ) + + // GIVEN the vibrate icon is set to be hidden + fakeSecureSettingsRepository.setInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) + + val latest by collectLastValue(underTest.iconBlockList) + + // THEN the volume is in the blocklist + assertThat(latest).containsExactly("test1", "test2", "volume") + } + + @Test + fun iconBlockList_updatesWithVolumeSetting() = + kosmos.runTest { + // GIVEN a list of blocked icons + overrideResource( + R.array.config_collapsed_statusbar_icon_blocklist, + arrayOf("test1", "test2"), + ) + + fakeSecureSettingsRepository.setInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) + + val latest by collectLastValue(underTest.iconBlockList) + + // Initially blocked + assertThat(latest).containsExactly("test1", "test2", "volume") + + // Setting updates + fakeSecureSettingsRepository.setInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 1) + + // Not blocked + assertThat(latest).containsExactly("test1", "test2") + + // Setting updates again + fakeSecureSettingsRepository.setInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) + + // ... blocked + assertThat(latest).containsExactly("test1", "test2", "volume") + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorTest.kt new file mode 100644 index 000000000000..e4963758d30b --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorTest.kt @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.domain.interactor + +import android.app.StatusBarManager.DISABLE2_NONE +import android.app.StatusBarManager.DISABLE_CLOCK +import android.app.StatusBarManager.DISABLE_NONE +import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS +import android.app.StatusBarManager.DISABLE_SYSTEM_INFO +import android.telephony.CarrierConfigManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel +import com.android.systemui.statusbar.pipeline.airplane.data.repository.airplaneModeRepository +import com.android.systemui.statusbar.pipeline.airplane.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig +import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.configWithOverride +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor +import com.android.systemui.statusbar.pipeline.shared.connectivityConstants +import com.android.systemui.statusbar.pipeline.shared.fake +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HomeStatusBarInteractorTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + val disableFlagsRepo = kosmos.fakeDisableFlagsRepository + + val underTest = kosmos.homeStatusBarInteractor + + @Test + fun visibilityViaDisableFlags_allDisabled() = + kosmos.runTest { + val latest by collectLastValue(underTest.visibilityViaDisableFlags) + + disableFlagsRepo.disableFlags.value = + DisableFlagsModel( + DISABLE_CLOCK or DISABLE_NOTIFICATION_ICONS or DISABLE_SYSTEM_INFO, + DISABLE2_NONE, + animate = false, + ) + + assertThat(latest!!.isClockAllowed).isFalse() + assertThat(latest!!.areNotificationIconsAllowed).isFalse() + assertThat(latest!!.isSystemInfoAllowed).isFalse() + } + + @Test + fun visibilityViaDisableFlags_allEnabled() = + kosmos.runTest { + val latest by collectLastValue(underTest.visibilityViaDisableFlags) + + disableFlagsRepo.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false) + + assertThat(latest!!.isClockAllowed).isTrue() + assertThat(latest!!.areNotificationIconsAllowed).isTrue() + assertThat(latest!!.isSystemInfoAllowed).isTrue() + } + + @Test + fun visibilityViaDisableFlags_animateFalse() = + kosmos.runTest { + val latest by collectLastValue(underTest.visibilityViaDisableFlags) + + disableFlagsRepo.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = false) + + assertThat(latest!!.animate).isFalse() + } + + @Test + fun visibilityViaDisableFlags_animateTrue() = + kosmos.runTest { + val latest by collectLastValue(underTest.visibilityViaDisableFlags) + + disableFlagsRepo.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE, animate = true) + + assertThat(latest!!.animate).isTrue() + } + + @Test + fun shouldShowOperatorName_trueIfCarrierConfigSaysSoAndDeviceHasData() = + kosmos.runTest { + // GIVEN default data subId is 1 + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + // GIVEN Config is enabled + carrierConfigRepository.fake.configsById[1] = + SystemUiCarrierConfig( + 1, + configWithOverride( + CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, + true, + ), + ) + + // GIVEN airplane mode is off + airplaneModeRepository.fake.isAirplaneMode.value = false + + // GIVEN hasDataCapabilities is true + connectivityConstants.fake.hasDataCapabilities = true + + val latest by collectLastValue(underTest.shouldShowOperatorName) + + // THEN we should show the operator name + assertThat(latest).isTrue() + } + + @Test + fun shouldShowOperatorName_falseNoDataCapabilities() = + kosmos.runTest { + // GIVEN default data subId is 1 + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + // GIVEN Config is enabled + carrierConfigRepository.fake.configsById[1] = + SystemUiCarrierConfig( + 1, + configWithOverride( + CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, + true, + ), + ) + + // GIVEN airplane mode is off + airplaneModeRepository.fake.isAirplaneMode.value = true + + // WHEN hasDataCapabilities is false + connectivityConstants.fake.hasDataCapabilities = false + + val latest by collectLastValue(underTest.shouldShowOperatorName) + + // THEN we should not show the operator name + assertThat(latest).isFalse() + } + + @Test + fun shouldShowOperatorName_falseWhenConfigIsOff() = + kosmos.runTest { + // GIVEN default data subId is 1 + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + // GIVEN airplane mode is off + airplaneModeRepository.fake.isAirplaneMode.value = false + + // WHEN Config is disabled + carrierConfigRepository.fake.configsById[1] = + SystemUiCarrierConfig( + 1, + configWithOverride( + CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, + false, + ), + ) + + val latest by collectLastValue(underTest.shouldShowOperatorName) + + // THEN we should not show the operator name + assertThat(latest).isFalse() + } + + @Test + fun shouldShowOperatorName_falseIfAirplaneMode() = + kosmos.runTest { + // GIVEN default data subId is 1 + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + // GIVEN Config is enabled + carrierConfigRepository.fake.configsById[1] = + SystemUiCarrierConfig( + 1, + configWithOverride( + CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, + true, + ), + ) + + // WHEN airplane mode is on + airplaneModeRepository.fake.isAirplaneMode.value = true + + val latest by collectLastValue(underTest.shouldShowOperatorName) + + // THEN we should not show the operator name + assertThat(latest).isFalse() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt index eef5753cef8a..0aaf89a4c382 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,10 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel +import android.graphics.Color +import android.graphics.Rect import android.view.View +import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle @@ -24,7 +27,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -class FakeHomeStatusBarViewModel : HomeStatusBarViewModel { +class FakeHomeStatusBarViewModel( + override val operatorNameViewModel: StatusBarOperatorNameViewModel +) : HomeStatusBarViewModel { private val areNotificationLightsOut = MutableStateFlow(false) override val isTransitioningFromLockscreenToOccluded = MutableStateFlow(false) @@ -38,6 +43,8 @@ class FakeHomeStatusBarViewModel : HomeStatusBarViewModel { override val isHomeStatusBarAllowedByScene = MutableStateFlow(false) + override val shouldShowOperatorNameView = MutableStateFlow(false) + override val isClockVisible = MutableStateFlow( HomeStatusBarViewModel.VisibilityModel( @@ -65,5 +72,23 @@ class FakeHomeStatusBarViewModel : HomeStatusBarViewModel { ) ) + override val iconBlockList: MutableStateFlow<List<String>> = MutableStateFlow(listOf()) + override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut + + val darkRegions = mutableListOf<Rect>() + + var darkIconTint = Color.BLACK + var lightIconTint = Color.WHITE + + override fun areaTint(displayId: Int): Flow<StatusBarTintColor> = + MutableStateFlow( + StatusBarTintColor { viewBounds -> + if (DarkIconDispatcher.isInAreas(darkRegions, viewBounds)) { + lightIconTint + } else { + darkIconTint + } + } + ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt index 5c1141b94bc8..e91875cd0885 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt @@ -22,6 +22,7 @@ import android.app.StatusBarManager.DISABLE_CLOCK import android.app.StatusBarManager.DISABLE_NONE import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS import android.app.StatusBarManager.DISABLE_SYSTEM_INFO +import android.graphics.Rect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View @@ -45,6 +46,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.log.assertLogsWtf import com.android.systemui.mediaprojection.data.model.MediaProjectionState import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository +import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.scene.data.repository.sceneContainerRepository import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.screenrecord.data.model.ScreenRecordModel @@ -73,6 +75,10 @@ import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository +import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher +import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarIconBlockList +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarInteractorShowOperatorName import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel.VisibilityModel import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -496,6 +502,72 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { } @Test + fun shouldShowOperatorNameView_allowedByInteractor_allowedByDisableFlags_visible() = + kosmos.runTest { + kosmos.setHomeStatusBarInteractorShowOperatorName(true) + + val latest by collectLastValue(underTest.shouldShowOperatorNameView) + transitionKeyguardToGone() + + fakeDisableFlagsRepository.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE) + + assertThat(latest).isTrue() + } + + @Test + fun shouldShowOperatorNameView_disAllowedByInteractor_allowedByDisableFlags_notVisible() = + kosmos.runTest { + kosmos.setHomeStatusBarInteractorShowOperatorName(false) + + transitionKeyguardToGone() + + fakeDisableFlagsRepository.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE) + + val latest by collectLastValue(underTest.shouldShowOperatorNameView) + + assertThat(latest).isFalse() + } + + @Test + fun shouldShowOperatorNameView_allowedByInteractor_disallowedByDisableFlags_notVisible() = + kosmos.runTest { + kosmos.setHomeStatusBarInteractorShowOperatorName(true) + + val latest by collectLastValue(underTest.shouldShowOperatorNameView) + transitionKeyguardToGone() + + fakeDisableFlagsRepository.disableFlags.value = + DisableFlagsModel(DISABLE_SYSTEM_INFO, DISABLE2_NONE) + + assertThat(latest).isFalse() + } + + @Test + fun shouldShowOperatorNameView_allowedByInteractor_hunPinned_false() = + kosmos.runTest { + kosmos.setHomeStatusBarInteractorShowOperatorName(false) + + transitionKeyguardToGone() + + fakeDisableFlagsRepository.disableFlags.value = + DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE) + + // there is an active HUN + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + val latest by collectLastValue(underTest.shouldShowOperatorNameView) + + assertThat(latest).isFalse() + } + + @Test fun isClockVisible_allowedByDisableFlags_visible() = kosmos.runTest { val latest by collectLastValue(underTest.isClockVisible) @@ -930,6 +1002,66 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE) } + @Test + fun areaTint_viewIsInDarkBounds_getsDarkTint() = + kosmos.runTest { + val displayId = 321 + fakeDarkIconRepository.darkState(displayId).value = + SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC) + + val areaTint by collectLastValue(underTest.areaTint(displayId)) + + val tint = areaTint?.tint(Rect(1, 1, 3, 3)) + + assertThat(tint).isEqualTo(0xAABBCC) + } + + @Test + fun areaTint_viewIsNotInDarkBounds_getsDefaultTint() = + kosmos.runTest { + val displayId = 321 + fakeDarkIconRepository.darkState(displayId).value = + SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC) + + val areaTint by collectLastValue(underTest.areaTint(displayId)) + + val tint = areaTint?.tint(Rect(6, 6, 7, 7)) + + assertThat(tint).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) + } + + @Test + fun areaTint_viewIsInDarkBounds_darkBoundsChange_viewUpdates() = + kosmos.runTest { + val displayId = 321 + fakeDarkIconRepository.darkState(displayId).value = + SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC) + + val areaTint by collectLastValue(underTest.areaTint(displayId)) + + var tint = areaTint?.tint(Rect(1, 1, 3, 3)) + + assertThat(tint).isEqualTo(0xAABBCC) + + // Dark region moves 5px to the right + fakeDarkIconRepository.darkState(displayId).value = + SysuiDarkIconDispatcher.DarkChange(listOf(Rect(5, 0, 10, 5)), 0f, 0xAABBCC) + + tint = areaTint?.tint(Rect(1, 1, 3, 3)) + + assertThat(tint).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) + } + + @Test + fun iconBlockList_followsInteractor() = + kosmos.runTest { + setHomeStatusBarIconBlockList(listOf("icon1", "icon2")) + + val latest by collectLastValue(underTest.iconBlockList) + + assertThat(latest).containsExactly("icon1", "icon2") + } + private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) = ActiveNotificationsStore.Builder() .apply { notifications.forEach(::addIndividualNotif) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt new file mode 100644 index 000000000000..20cc85f08b01 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class StatusBarOperatorNameViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val Kosmos.underTest by Kosmos.Fixture { kosmos.statusBarOperatorNameViewModel } + + @Test + fun operatorName_tracksDefaultDataCarrierName() = + kosmos.runTest { + val intr1 = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(1) + val intr2 = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(2) + val invalidIntr = fakeMobileIconsInteractor.getMobileConnectionInteractorForSubId(-1) + + // GIVEN default data subId is 1 + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + + intr1.carrierName.value = "Test Name 1" + intr2.carrierName.value = "Test Name 2" + invalidIntr.carrierName.value = "default network name" + + val latest by collectLastValue(underTest.operatorName) + + assertThat(latest).isEqualTo("Test Name 1") + + fakeMobileIconsInteractor.defaultDataSubId.value = 2 + + assertThat(latest).isEqualTo("Test Name 2") + + fakeMobileIconsInteractor.defaultDataSubId.value = -1 + + assertThat(latest).isEqualTo("default network name") + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt deleted file mode 100644 index 9f74915b4d1b..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.policy - -import android.content.Context -import android.content.pm.UserInfo -import android.graphics.Bitmap -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.internal.util.UserIcons -import com.android.systemui.res.R -import com.android.systemui.SysuiTestCase -import com.android.systemui.qs.tiles.UserDetailItemView -import com.android.systemui.user.data.source.UserRecord -import com.android.systemui.util.mockito.whenever -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` -import org.mockito.MockitoAnnotations - -@RunWith(AndroidJUnit4::class) -@SmallTest -class KeyguardUserSwitcherAdapterTest : SysuiTestCase() { - @Mock - private lateinit var userSwitcherController: UserSwitcherController - @Mock - private lateinit var parent: ViewGroup - @Mock - private lateinit var keyguardUserDetailItemView: KeyguardUserDetailItemView - @Mock - private lateinit var otherView: View - @Mock - private lateinit var inflatedUserDetailItemView: KeyguardUserDetailItemView - @Mock - private lateinit var layoutInflater: LayoutInflater - @Mock - private lateinit var keyguardUserSwitcherController: KeyguardUserSwitcherController - - private lateinit var adapter: KeyguardUserSwitcherController.KeyguardUserAdapter - private lateinit var picture: Bitmap - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - whenever(userSwitcherController.isUserSwitcherEnabled).thenReturn(true) - - mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, layoutInflater) - `when`(layoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean())) - .thenReturn(inflatedUserDetailItemView) - adapter = KeyguardUserSwitcherController.KeyguardUserAdapter( - mContext, - mContext.resources, - LayoutInflater.from(mContext), - userSwitcherController, keyguardUserSwitcherController) - picture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user)) - } - - /** - * Uses the KeyguardUserAdapter to create a UserDetailItemView where the convertView has an - * incompatible type - */ - private fun createViewFromDifferentType( - isCurrentUser: Boolean, - isGuestUser: Boolean - ): UserDetailItemView? { - val user = createUserRecord(isCurrentUser, isGuestUser) - return adapter.createUserDetailItemView(otherView, parent, user) - } - - /** - * Uses the KeyguardUserAdapter to create a UserDetailItemView where the convertView is an - * instance of KeyguardUserDetailItemView - */ - private fun createViewFromSameType( - isCurrentUser: Boolean, - isGuestUser: Boolean - ): UserDetailItemView? { - val user = createUserRecord(isCurrentUser, isGuestUser) - return adapter.createUserDetailItemView(keyguardUserDetailItemView, parent, user) - } - - @Test - fun shouldSetOnClickListener_notCurrentUser_notGuestUser_oldViewIsSameType() { - val v: UserDetailItemView? = createViewFromSameType( - isCurrentUser = false, isGuestUser = false) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnClickListener_notCurrentUser_guestUser_oldViewIsSameType() { - val v: UserDetailItemView? = createViewFromSameType( - isCurrentUser = false, isGuestUser = true) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnOnClickListener_currentUser_notGuestUser_oldViewIsSameType() { - val v: UserDetailItemView? = createViewFromSameType( - isCurrentUser = true, isGuestUser = false) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnClickListener_currentUser_guestUser_oldViewIsSameType() { - val v: UserDetailItemView? = createViewFromSameType( - isCurrentUser = true, isGuestUser = true) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnClickListener_notCurrentUser_notGuestUser_oldViewIsDifferentType() { - val v: UserDetailItemView? = createViewFromDifferentType( - isCurrentUser = false, isGuestUser = false) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnClickListener_notCurrentUser_guestUser_oldViewIsDifferentType() { - val v: UserDetailItemView? = createViewFromDifferentType( - isCurrentUser = false, isGuestUser = true) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnOnClickListener_currentUser_notGuestUser_oldViewIsDifferentType() { - val v: UserDetailItemView? = createViewFromDifferentType( - isCurrentUser = true, isGuestUser = false) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun shouldSetOnClickListener_currentUser_guestUser_oldViewIsDifferentType() { - val v: UserDetailItemView? = createViewFromDifferentType( - isCurrentUser = true, isGuestUser = true) - assertNotNull(v) - verify(v)!!.setOnClickListener(adapter) - } - - @Test - fun testCurrentUserIsAlwaysFirst() { - `when`(userSwitcherController.users).thenReturn(arrayListOf( - createUserRecord(isCurrentUser = false, isGuestUser = false), - createUserRecord(isCurrentUser = true, isGuestUser = false), - createUserRecord(isCurrentUser = false, isGuestUser = true), - createUserRecord(isCurrentUser = false, isGuestUser = false) - )) - - adapter.notifyDataSetChanged() - assertTrue("Expected current user to be first in list", adapter.getItem(0).isCurrent) - assertFalse("Did not expect current user in position 1", adapter.getItem(1).isCurrent) - assertFalse("Did not expect current user in position 2", adapter.getItem(2).isCurrent) - assertTrue("Expected guest user to remain in position 2", adapter.getItem(2).isGuest) - assertFalse("Did not expect current user in position 3", adapter.getItem(3).isCurrent) - } - - private fun createUserRecord(isCurrentUser: Boolean, isGuestUser: Boolean) = - UserRecord( - UserInfo(0 /* id */, "name", 0 /* flags */), - picture, - isGuestUser, - isCurrentUser, - false /* isAddUser */, - false /* isRestricted */, - true /* isSwitchToEnabled */, - false /* isAddSupervisedUser */ - ) -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt index 06b3b57bd133..b2378d2c3aae 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.kosmos.mainCoroutineContext import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.runOnMainThreadAndWaitForIdleSync +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.systemUIDialogFactory import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.modesDialogViewModel @@ -78,6 +79,7 @@ class ModesDialogDelegateTest : SysuiTestCase() { { kosmos.modesDialogViewModel }, mockDialogEventLogger, kosmos.mainCoroutineContext, + kosmos.shadeDialogContextInteractor, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 7b52dd836b51..5cd0846ded7e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -501,6 +501,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @Test + @DisableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI) public void onWallpaperColorsChanged_changeLockWallpaper() { // Should ask for a new theme when wallpaper colors change WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt new file mode 100644 index 000000000000..f90e14caca75 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModelTest.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.touchpad.tutorial.ui.viewmodel + +import android.view.MotionEvent +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.common.ui.domain.interactor.configurationInteractor +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.res.R +import com.android.systemui.testKosmos +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress +import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE +import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class BackGestureScreenViewModelTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val fakeConfigRepository = kosmos.fakeConfigurationRepository + private val viewModel = BackGestureScreenViewModel(kosmos.configurationInteractor) + + @Before + fun before() { + setThresholdResource(threshold = SWIPE_DISTANCE - 1) + kosmos.useUnconfinedTestDispatcher() + } + + @Test + fun easterEggNotTriggeredAtStart() = + kosmos.runTest { + val easterEggTriggered by collectLastValue(viewModel.easterEggTriggered) + assertThat(easterEggTriggered).isFalse() + } + + @Test + fun emitsProgressStateWithLeftProgressAnimation() = + kosmos.runTest { + assertProgressWhileMovingFingers( + deltaX = -SWIPE_DISTANCE, + expected = + InProgress( + progress = 1f, + progressStartMarker = "gesture to L", + progressEndMarker = "end progress L", + ), + ) + } + + @Test + fun emitsProgressStateWithRightProgressAnimation() = + kosmos.runTest { + assertProgressWhileMovingFingers( + deltaX = SWIPE_DISTANCE, + expected = + InProgress( + progress = 1f, + progressStartMarker = "gesture to R", + progressEndMarker = "end progress R", + ), + ) + } + + @Test + fun emitsFinishedStateWithLeftSuccessAnimation() = + kosmos.runTest { + assertStateAfterEvents( + events = ThreeFingerGesture.swipeLeft(), + expected = Finished(successAnimation = R.raw.trackpad_back_success_left), + ) + } + + @Test + fun emitsFinishedStateWithRightSuccessAnimation() = + kosmos.runTest { + assertStateAfterEvents( + events = ThreeFingerGesture.swipeRight(), + expected = Finished(successAnimation = R.raw.trackpad_back_success_right), + ) + } + + @Test + fun gestureRecognitionTakesLatestDistanceThresholdIntoAccount() = + kosmos.runTest { + fun performBackGesture() = + ThreeFingerGesture.swipeLeft().forEach { viewModel.handleEvent(it) } + val state by collectLastValue(viewModel.gestureUiState) + performBackGesture() + assertThat(state).isInstanceOf(Finished::class.java) + + setThresholdResource(SWIPE_DISTANCE + 1) + performBackGesture() // now swipe distance is not enough to trigger success + + assertThat(state).isInstanceOf(Error::class.java) + } + + private fun setThresholdResource(threshold: Float) { + fakeConfigRepository.setDimensionPixelSize( + R.dimen.touchpad_tutorial_gestures_distance_threshold, + (threshold).toInt(), + ) + fakeConfigRepository.onAnyConfigurationChange() + } + + private fun Kosmos.assertProgressWhileMovingFingers(deltaX: Float, expected: GestureUiState) { + assertStateAfterEvents( + events = ThreeFingerGesture.eventsForGestureInProgress { move(deltaX = deltaX) }, + expected = expected, + ) + } + + private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) { + val state by collectLastValue(viewModel.gestureUiState) + events.forEach { viewModel.handleEvent(it) } + assertThat(state).isEqualTo(expected) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt new file mode 100644 index 000000000000..3c06352ace97 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModelTest.kt @@ -0,0 +1,154 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.content.res.mockResources +import android.view.MotionEvent +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.common.ui.domain.interactor.configurationInteractor +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.res.R +import com.android.systemui.testKosmos +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress +import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE +import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture +import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity +import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HomeGestureScreenViewModelTest : SysuiTestCase() { + + companion object { + const val GESTURE_VELOCITY = 1f + const val LOW_VELOCITY_THRESHOLD = GESTURE_VELOCITY - 0.01f + const val TOO_HIGH_VELOCITY_THRESHOLD = GESTURE_VELOCITY + 0.01f + } + + private val kosmos = testKosmos() + private val fakeConfigRepository = kosmos.fakeConfigurationRepository + private val fakeVelocityTracker = kosmos.fakeVelocityTracker + private val resources = kosmos.mockResources + + private val viewModel = + HomeGestureScreenViewModel(kosmos.configurationInteractor, resources, fakeVelocityTracker) + + @Before + fun before() { + setDistanceThreshold(threshold = SWIPE_DISTANCE - 1) + setVelocityThreshold(threshold = LOW_VELOCITY_THRESHOLD) + fakeVelocityTracker.setVelocity(Velocity(GESTURE_VELOCITY)) + kosmos.useUnconfinedTestDispatcher() + } + + @Test + fun easterEggNotTriggeredAtStart() = + kosmos.runTest { + val easterEggTriggered by collectLastValue(viewModel.easterEggTriggered) + assertThat(easterEggTriggered).isFalse() + } + + @Test + fun emitsProgressStateWithAnimationMarkers() = + kosmos.runTest { + assertStateAfterEvents( + events = + ThreeFingerGesture.eventsForGestureInProgress { + move(deltaY = -SWIPE_DISTANCE) + }, + expected = + InProgress( + progress = 1f, + progressStartMarker = "drag with gesture", + progressEndMarker = "release playback realtime", + ), + ) + } + + @Test + fun emitsFinishedStateWithSuccessAnimation() = + kosmos.runTest { + assertStateAfterEvents( + events = ThreeFingerGesture.swipeUp(), + expected = Finished(successAnimation = R.raw.trackpad_home_success), + ) + } + + private fun performHomeGesture() { + ThreeFingerGesture.swipeUp().forEach { viewModel.handleEvent(it) } + } + + @Test + fun gestureRecognitionTakesLatestDistanceThresholdIntoAccount() = + kosmos.runTest { + val state by collectLastValue(viewModel.gestureUiState) + performHomeGesture() + assertThat(state).isInstanceOf(Finished::class.java) + + setDistanceThreshold(SWIPE_DISTANCE + 1) + performHomeGesture() // now swipe distance is not enough to trigger success + + assertThat(state).isInstanceOf(Error::class.java) + } + + @Test + fun gestureRecognitionTakesLatestVelocityThresholdIntoAccount() = + kosmos.runTest { + val state by collectLastValue(viewModel.gestureUiState) + performHomeGesture() + assertThat(state).isInstanceOf(Finished::class.java) + + setVelocityThreshold(TOO_HIGH_VELOCITY_THRESHOLD) + performHomeGesture() + + assertThat(state).isInstanceOf(Error::class.java) + } + + private fun setDistanceThreshold(threshold: Float) { + fakeConfigRepository.setDimensionPixelSize( + R.dimen.touchpad_tutorial_gestures_distance_threshold, + (threshold).toInt(), + ) + fakeConfigRepository.onAnyConfigurationChange() + } + + private fun setVelocityThreshold(threshold: Float) { + whenever(resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold)) + .thenReturn(threshold) + fakeConfigRepository.onAnyConfigurationChange() + } + + private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) { + val state by collectLastValue(viewModel.gestureUiState) + events.forEach { viewModel.handleEvent(it) } + assertThat(state).isEqualTo(expected) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt new file mode 100644 index 000000000000..a2d8a8b3cb0e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModelTest.kt @@ -0,0 +1,160 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.content.res.mockResources +import android.view.MotionEvent +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.common.ui.domain.interactor.configurationInteractor +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.res.R +import com.android.systemui.testKosmos +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress +import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE +import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture +import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity +import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class RecentAppsGestureScreenViewModelTest : SysuiTestCase() { + + companion object { + const val GESTURE_VELOCITY = 1f + const val VELOCITY_THRESHOLD = GESTURE_VELOCITY + 0.01f + const val TOO_LOW_VELOCITY_THRESHOLD = GESTURE_VELOCITY - 0.01f + } + + private val kosmos = testKosmos() + private val fakeConfigRepository = kosmos.fakeConfigurationRepository + private val fakeVelocityTracker = kosmos.fakeVelocityTracker + private val resources = kosmos.mockResources + + private val viewModel = + RecentAppsGestureScreenViewModel( + kosmos.configurationInteractor, + resources, + fakeVelocityTracker, + ) + + @Before + fun before() { + setDistanceThreshold(threshold = SWIPE_DISTANCE - 1) + setVelocityThreshold(threshold = VELOCITY_THRESHOLD) + fakeVelocityTracker.setVelocity(Velocity(GESTURE_VELOCITY)) + kosmos.useUnconfinedTestDispatcher() + } + + @Test + fun easterEggNotTriggeredAtStart() = + kosmos.runTest { + val easterEggTriggered by collectLastValue(viewModel.easterEggTriggered) + assertThat(easterEggTriggered).isFalse() + } + + @Test + fun emitsProgressStateWithAnimationMarkers() = + kosmos.runTest { + assertStateAfterEvents( + events = + ThreeFingerGesture.eventsForGestureInProgress { + move(deltaY = -SWIPE_DISTANCE) + }, + expected = + InProgress( + progress = 1f, + progressStartMarker = "drag with gesture", + progressEndMarker = "onPause", + ), + ) + } + + @Test + fun emitsFinishedStateWithSuccessAnimation() = + kosmos.runTest { + assertStateAfterEvents( + events = ThreeFingerGesture.swipeUp(), + expected = Finished(successAnimation = R.raw.trackpad_recent_apps_success), + ) + } + + private fun performRecentAppsGesture() { + ThreeFingerGesture.swipeUp().forEach { viewModel.handleEvent(it) } + } + + @Test + fun gestureRecognitionTakesLatestDistanceThresholdIntoAccount() = + kosmos.runTest { + val state by collectLastValue(viewModel.gestureUiState) + performRecentAppsGesture() + assertThat(state).isInstanceOf(Finished::class.java) + + setDistanceThreshold(SWIPE_DISTANCE + 1) + performRecentAppsGesture() // now swipe distance is not enough to trigger success + + assertThat(state).isInstanceOf(Error::class.java) + } + + @Test + fun gestureRecognitionTakesLatestVelocityThresholdIntoAccount() = + kosmos.runTest { + val state by collectLastValue(viewModel.gestureUiState) + performRecentAppsGesture() + assertThat(state).isInstanceOf(Finished::class.java) + + setVelocityThreshold(TOO_LOW_VELOCITY_THRESHOLD) + performRecentAppsGesture() + + assertThat(state).isInstanceOf(Error::class.java) + } + + private fun setDistanceThreshold(threshold: Float) { + whenever( + resources.getDimensionPixelSize( + R.dimen.touchpad_tutorial_gestures_distance_threshold + ) + ) + .thenReturn(threshold.toInt()) + fakeConfigRepository.onAnyConfigurationChange() + } + + private fun setVelocityThreshold(threshold: Float) { + whenever(resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)) + .thenReturn(threshold) + fakeConfigRepository.onAnyConfigurationChange() + } + + private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) { + val state by collectLastValue(viewModel.gestureUiState) + events.forEach { viewModel.handleEvent(it) } + assertThat(state).isEqualTo(expected) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt index d5651ec8ce6c..e2f363bf9f64 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt @@ -52,7 +52,7 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) class GuestUserInteractorTest : SysuiTestCase() { @Mock private lateinit var manager: UserManager diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt index 3f995c69c32f..87d782e7815d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt @@ -172,9 +172,9 @@ class VolumeDialogSlidersInteractorTest : SysuiTestCase() { runCurrent() assertThat(slidersModel!!.slider) - .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC)) + .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM)) assertThat(slidersModel!!.floatingSliders) - .containsExactly(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM)) + .containsExactly(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC)) } } } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index abb721ab0dd8..55be9f79e598 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -16,6 +16,7 @@ package com.android.systemui.plugins; import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; @@ -33,6 +34,22 @@ import com.android.systemui.plugins.annotations.ProvidesInterface; public interface ActivityStarter { int VERSION = 2; + /** + * Registers the given {@link ActivityTransitionAnimator.ControllerFactory} for launching and + * closing transitions matching the {@link ActivityTransitionAnimator.TransitionCookie} and the + * {@link ComponentName} that it contains. + */ + void registerTransition( + ActivityTransitionAnimator.TransitionCookie cookie, + ActivityTransitionAnimator.ControllerFactory controllerFactory); + + /** + * Unregisters the {@link ActivityTransitionAnimator.ControllerFactory} previously registered + * containing the given {@link ActivityTransitionAnimator.TransitionCookie}. If no such + * registration exists, this is a no-op. + */ + void unregisterTransition(ActivityTransitionAnimator.TransitionCookie cookie); + void startPendingIntentDismissingKeyguard(PendingIntent intent); /** diff --git a/packages/SystemUI/plugin_core/processor/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt b/packages/SystemUI/plugin_core/processor/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt index 6b54d8936254..d93f7d3093b8 100644 --- a/packages/SystemUI/plugin_core/processor/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt +++ b/packages/SystemUI/plugin_core/processor/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt @@ -33,9 +33,10 @@ import kotlin.collections.ArrayDeque /** * [ProtectedPluginProcessor] generates a proxy implementation for interfaces annotated with - * [ProtectedInterface] which catches [LinkageError]s generated by the proxied target. This protects - * the plugin host from crashing due to out-of-date plugin code, where some call has changed so that - * the [ClassLoader] can no longer resolve it correctly. + * [ProtectedInterface] which catches [Exception]s generated by the proxied target. Production + * plugin interfaces should use this to catch [LinkagError]s as that protects the plugin host from + * crashing due to out-of-date plugin code, where some call has changed so that the [ClassLoader] is + * no longer able to resolve it correctly. * * [PluginInstance] observes these failures via [ProtectedMethodListener] and unloads the plugin in * question to prevent further issues. This persists through further load/unload requests. @@ -61,6 +62,7 @@ class ProtectedPluginProcessor : AbstractProcessor() { val sourcePkg: String, val sourceName: String, val outputName: String, + val exTypeAttr: ProtectedInterface, ) override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean { @@ -68,10 +70,19 @@ class ProtectedPluginProcessor : AbstractProcessor() { val additionalImports = mutableSetOf<String>() for (attr in annotations) { for (target in roundEnv.getElementsAnnotatedWith(attr)) { + // Find the target exception types to be used + var exTypeAttr = target.getAnnotation(ProtectedInterface::class.java) + if (exTypeAttr == null || exTypeAttr.exTypes.size == 0) { + exTypeAttr = ProtectedInterface.Default + } + val sourceName = "${target.simpleName}" val outputName = "${sourceName}Protector" val pkg = (target.getEnclosingElement() as PackageElement).qualifiedName.toString() - targets.put("$target", TargetData(attr, target, pkg, sourceName, outputName)) + targets.put( + "$target", + TargetData(attr, target, pkg, sourceName, outputName, exTypeAttr), + ) // This creates excessive imports, but it should be fine additionalImports.add("$pkg.$sourceName") @@ -80,7 +91,7 @@ class ProtectedPluginProcessor : AbstractProcessor() { } if (targets.size <= 0) return false - for ((_, sourceType, sourcePkg, sourceName, outputName) in targets.values) { + for ((_, sourceType, sourcePkg, sourceName, outputName, exTypeAttr) in targets.values) { // Find all methods in this type and all super types to that need to be implemented val types = ArrayDeque<TypeMirror>().apply { addLast(sourceType.asType()) } val impAttrs = mutableListOf<GeneratedImport>() @@ -105,7 +116,6 @@ class ProtectedPluginProcessor : AbstractProcessor() { // Imports used by the proxy implementation line("import android.util.Log;") - line("import java.lang.LinkageError;") line("import com.android.systemui.plugins.PluginWrapper;") line("import com.android.systemui.plugins.ProtectedPluginListener;") line() @@ -118,6 +128,14 @@ class ProtectedPluginProcessor : AbstractProcessor() { line() } + // Imports of caught exceptions + if (exTypeAttr.exTypes.size > 0) { + for (exType in exTypeAttr.exTypes) { + line("import $exType;") + } + line() + } + // Imports declared via @GeneratedImport if (impAttrs.size > 0) { for (impAttr in impAttrs) { @@ -232,11 +250,14 @@ class ProtectedPluginProcessor : AbstractProcessor() { // Protect callsite in try/catch block braceBlock("try") { line(callStatement) } - // Notify listener when a LinkageError is caught - braceBlock("catch (LinkageError ex)") { - line("Log.wtf(CLASS, \"Failed to execute: \" + METHOD, ex);") - line("mHasError = mListener.onFail(CLASS, METHOD, ex);") - line(errorStatement) + // Notify listener when a target exception is caught + for (exType in exTypeAttr.exTypes) { + val simpleName = exType.substringAfterLast(".") + braceBlock("catch ($simpleName ex)") { + line("Log.wtf(CLASS, \"Failed to execute: \" + METHOD, ex);") + line("mHasError = mListener.onFail(CLASS, METHOD, ex);") + line(errorStatement) + } } } line() diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt index 3a1f251ca672..8e2528f59f7d 100644 --- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt @@ -16,12 +16,11 @@ package com.android.systemui.plugins /** Listener for events from proxy types generated by [ProtectedPluginProcessor]. */ interface ProtectedPluginListener { /** - * Called when a method call produces a [LinkageError] before returning. This callback is - * provided so that the host application can terminate the plugin or log the error as - * appropriate. + * Called when a method call produces a [Exception] before returning. This callback is provided + * so that the host application can terminate the plugin or log the error as appropriate. * * @return true to terminate all methods within this object; false if the error is recoverable * and the proxied plugin should continue to operate as normal. */ - fun onFail(className: String, methodName: String, failure: LinkageError): Boolean + fun onFail(className: String, methodName: String, failure: Throwable): Boolean } diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt index 12a977d9350e..dc2ea8c3bd7d 100644 --- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt @@ -15,11 +15,15 @@ package com.android.systemui.plugins.annotations /** * This annotation marks denotes that an interface should use a proxy layer to protect the plugin - * host from crashing due to [LinkageError]s originating within the plugin's implementation. + * host from crashing due to the [Exception] types originating within the plugin's implementation. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) -annotation class ProtectedInterface +annotation class ProtectedInterface(vararg val exTypes: String) { + companion object { + val Default = ProtectedInterface("java.lang.Exception", "java.lang.LinkageError") + } +} /** * This annotation specifies any additional imports that the processor will require when generating @@ -32,9 +36,9 @@ annotation class ProtectedInterface annotation class GeneratedImport(val extraImport: String) /** - * This annotation provides default values to return when the proxy implementation catches a - * [LinkageError]. The string specified should be a simple but valid java statement. In most cases - * it should be a return statement of the appropriate type, but in some cases throwing a known + * This annotation provides default values to return when the proxy implementation catches a target + * [Exception]. The string specified should be a simple but valid java statement. In most cases it + * should be a return statement of the appropriate type, but in some cases throwing a known * exception type may be preferred. * * This annotation is not required for methods that return void, but will behave the same way. diff --git a/packages/SystemUI/res/color/slider_active_track_color.xml b/packages/SystemUI/res/color/slider_active_track_color.xml deleted file mode 100644 index 8ba5e4901a7a..000000000000 --- a/packages/SystemUI/res/color/slider_active_track_color.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="@androidprv:color/materialColorPrimary" android:state_enabled="true" /> - <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" /> -</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/slider_inactive_track_color.xml b/packages/SystemUI/res/color/slider_inactive_track_color.xml deleted file mode 100644 index 7980f804a516..000000000000 --- a/packages/SystemUI/res/color/slider_inactive_track_color.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" android:state_enabled="true" /> - <item android:color="@androidprv:color/materialColorPrimary" /> -</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/slider_thumb_color.xml b/packages/SystemUI/res/color/slider_thumb_color.xml deleted file mode 100644 index 8a98902426f8..000000000000 --- a/packages/SystemUI/res/color/slider_thumb_color.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" android:state_enabled="false" /> - <item android:color="@androidprv:color/materialColorPrimary" /> -</selector> diff --git a/packages/SystemUI/res/drawable/audio_bars_idle.xml b/packages/SystemUI/res/drawable/audio_bars_idle.xml new file mode 100644 index 000000000000..92a24755fece --- /dev/null +++ b/packages/SystemUI/res/drawable/audio_bars_idle.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="168dp" + android:height="168dp" + android:viewportWidth="168" + android:viewportHeight="168"> + <group android:name="_R_G"> + <group + android:name="_R_G_L_2_G" + android:translateX="121.161" + android:translateY="83.911"> + <path + android:name="_R_G_L_2_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_1_G" + android:translateX="102.911" + android:translateY="83.911"> + <path + android:name="_R_G_L_1_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + <group + android:name="_R_G_L_0_G" + android:translateX="139.661" + android:translateY="83.911"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:fillAlpha="1" + android:fillColor="#ffffff" + android:fillType="nonZero" + android:pathData=" M-37.16 -5.87 C-33.94,-5.87 -31.32,-3.32 -31.2,-0.13 C-31.2,-0.06 -31.2,0.02 -31.2,0.09 C-31.2,0.16 -31.2,0.23 -31.2,0.29 C-31.31,3.49 -33.94,6.05 -37.16,6.05 C-40.39,6.05 -43.01,3.49 -43.12,0.29 C-43.12,0.23 -43.12,0.16 -43.12,0.09 C-43.12,0.01 -43.12,-0.07 -43.12,-0.15 C-42.99,-3.33 -40.37,-5.87 -37.16,-5.87c " /> + </group> + </group> + <group android:name="time_group" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml index dfefb9d166af..4b7be3512f53 100644 --- a/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml +++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml @@ -27,18 +27,7 @@ <solid android:color="@android:color/transparent"/> </shape> </item> - <item - android:end="20dp" - android:gravity="end|center_vertical"> - <vector - android:width="@dimen/hearing_devices_preset_spinner_icon_size" - android:height="@dimen/hearing_devices_preset_spinner_icon_size" - android:viewportWidth="24" - android:viewportHeight="24" - android:tint="?androidprv:attr/colorControlNormal"> - <path - android:fillColor="#FF000000" - android:pathData="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" /> - </vector> - </item> + <item android:end="20dp" + android:gravity="end|center_vertical" + android:drawable="@drawable/ic_hearing_device_expand" /> </layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_hearing_device_expand.xml b/packages/SystemUI/res/drawable/ic_hearing_device_expand.xml new file mode 100644 index 000000000000..fdfe7134a748 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_hearing_device_expand.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="@androidprv:color/materialColorOnSurface"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml deleted file mode 100644 index 9ce030e844d4..000000000000 --- a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<!-- LinearLayout --> -<com.android.systemui.statusbar.policy.KeyguardUserDetailItemView - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:padding="8dp" - android:layout_marginEnd="32dp" - android:gravity="end|center_vertical" - android:clickable="true" - android:background="@drawable/kg_user_switcher_rounded_bg" - sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" - sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"> - <TextView android:id="@+id/user_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="25dp" - android:layout_marginEnd="12dp" - /> - <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" - android:layout_width="@dimen/kg_framed_avatar_size" - android:layout_height="@dimen/kg_framed_avatar_size" - android:contentDescription="@null" - sysui:badgeDiameter="18dp" - sysui:badgeMargin="1dp" /> -</com.android.systemui.statusbar.policy.KeyguardUserDetailItemView> diff --git a/packages/SystemUI/res/layout/hearing_device_ambient_volume_layout.xml b/packages/SystemUI/res/layout/hearing_device_ambient_volume_layout.xml new file mode 100644 index 000000000000..fd409a5a8bb1 --- /dev/null +++ b/packages/SystemUI/res/layout/hearing_device_ambient_volume_layout.xml @@ -0,0 +1,67 @@ +<!-- + 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. +--> + +<LinearLayout + 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="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/ambient_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin" + android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin" + android:gravity="center_vertical" + android:orientation="horizontal"> + <ImageView + android:id="@+id/ambient_volume_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="12dp" + android:contentDescription="@string/hearing_devices_ambient_unmute" + android:src="@drawable/ic_ambient_volume" + android:tint="@androidprv:color/materialColorOnSurface" /> + <TextView + android:id="@+id/ambient_title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingStart="10dp" + android:text="@string/hearing_devices_ambient_label" + android:textAppearance="@style/TextAppearance.Dialog.Title" + android:textDirection="locale" + android:textSize="16sp" + android:gravity="center_vertical" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" /> + <ImageView + android:id="@+id/ambient_expand_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="10dp" + android:contentDescription="@string/hearing_devices_ambient_expand_controls" + android:src="@drawable/ic_hearing_device_expand" + android:tint="@androidprv:color/materialColorOnSurface" /> + </LinearLayout> + <LinearLayout + android:id="@+id/ambient_control_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/hearing_device_ambient_volume_slider.xml b/packages/SystemUI/res/layout/hearing_device_ambient_volume_slider.xml new file mode 100644 index 000000000000..44ada8943b12 --- /dev/null +++ b/packages/SystemUI/res/layout/hearing_device_ambient_volume_slider.xml @@ -0,0 +1,46 @@ +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin" + android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin" + android:orientation="vertical"> + + <TextView + android:id="@+id/ambient_volume_slider_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:paddingStart="@dimen/hearing_devices_small_title_padding_horizontal" + android:textAppearance="@style/TextAppearance.Dialog.Title" + android:textDirection="locale" + android:textSize="14sp" + android:labelFor="@+id/ambient_volume_slider" + android:gravity="center_vertical" /> + <com.google.android.material.slider.Slider + style="@style/SystemUI.Material3.Slider" + android:id="@+id/ambient_volume_slider" + android:layout_width="match_parent" + android:layout_height="@dimen/bluetooth_dialog_device_height" + android:layout_gravity="center_vertical" + android:theme="@style/Theme.Material3.DayNight" + app:labelBehavior="gone" /> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml index bf04a6f64d6a..949a6abb9b9d 100644 --- a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml +++ b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml @@ -85,13 +85,22 @@ android:longClickable="false"/> </LinearLayout> + <com.android.systemui.accessibility.hearingaid.AmbientVolumeLayout + android:id="@+id/ambient_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/preset_layout" + android:layout_marginTop="@dimen/hearing_devices_layout_margin" /> + <LinearLayout android:id="@+id/tools_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/preset_layout" + app:layout_constraintTop_toBottomOf="@id/ambient_layout" android:layout_marginTop="@dimen/hearing_devices_layout_margin" android:orientation="vertical"> <TextView diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml deleted file mode 100644 index 7aafd895f723..000000000000 --- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> -<!-- This is a view that shows a user switcher in Keyguard. --> -<com.android.systemui.statusbar.policy.KeyguardUserSwitcherView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/keyguard_user_switcher_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="end"> - - <com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView - android:id="@+id/keyguard_user_switcher_list" - android:orientation="vertical" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:layout_gravity="top|end" - android:gravity="end" /> - -</com.android.systemui.statusbar.policy.KeyguardUserSwitcherView> diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml deleted file mode 100644 index e39f1a9dd6fa..000000000000 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - ~ Copyright (C) 2014 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<!-- LinearLayout --> -<com.android.systemui.statusbar.policy.KeyguardUserDetailItemView - android:id="@+id/user_item" - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:padding="8dp" - android:layout_marginEnd="8dp" - android:gravity="end|center_vertical" - android:clickable="true" - android:background="@drawable/kg_user_switcher_rounded_bg" - systemui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" - systemui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"> - <TextView - android:id="@+id/user_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="20dp" - android:layout_marginEnd="16dp" /> - <com.android.systemui.statusbar.phone.UserAvatarView - android:id="@+id/user_picture" - android:layout_width="@dimen/kg_framed_avatar_size" - android:layout_height="@dimen/kg_framed_avatar_size" - systemui:avatarPadding="0dp" - systemui:badgeDiameter="18dp" - systemui:badgeMargin="1dp" - systemui:frameWidth="0dp" - systemui:framePadding="0dp" - systemui:frameColor="@color/kg_user_avatar_frame" /> -</com.android.systemui.statusbar.policy.KeyguardUserDetailItemView> diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml index 7745af9dd408..51217d4e27bd 100644 --- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml @@ -58,14 +58,14 @@ /> <!-- Shows generic text. --> - <TextView + <com.android.systemui.statusbar.chips.ui.view.ChipTextView android:id="@+id/ongoing_activity_chip_text" style="@style/StatusBar.Chip.Text.LimitedWidth" android:visibility="gone" /> <!-- Shows a time delta in short form, like "15min" or "1hr". --> - <android.widget.DateTimeView + <com.android.systemui.statusbar.chips.ui.view.ChipDateTimeView android:id="@+id/ongoing_activity_chip_short_time_delta" style="@style/StatusBar.Chip.Text.LimitedWidth" android:visibility="gone" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 77fbb642f664..46a9d475cbb6 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -31,12 +31,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - <ViewStub - android:id="@+id/keyguard_qs_user_switch_stub" - android:layout="@layout/keyguard_qs_user_switch" - android:layout_height="match_parent" - android:layout_width="match_parent" /> - <include layout="@layout/status_bar_expanded_plugin_frame"/> <com.android.systemui.shade.NotificationsQuickSettingsContainer @@ -120,12 +114,6 @@ /> </com.android.systemui.shade.NotificationsQuickSettingsContainer> - <ViewStub - android:id="@+id/keyguard_user_switcher_stub" - android:layout="@layout/keyguard_user_switcher" - android:layout_height="match_parent" - android:layout_width="match_parent" /> - <include layout="@layout/dock_info_bottom_area_overlay" /> <include diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index a3bad8f012ac..bad5711a1ccc 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -56,8 +56,8 @@ android:layout_marginTop="@dimen/volume_dialog_components_spacing" android:background="@drawable/ripple_drawable_20dp" android:contentDescription="@string/accessibility_volume_settings" + android:scaleType="centerInside" android:soundEffectsEnabled="false" - android:src="@drawable/horizontal_ellipsis" android:tint="@androidprv:color/materialColorPrimary" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" @@ -71,6 +71,9 @@ android:layout_height="0dp" android:layout_marginTop="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" android:layout_marginBottom="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" + android:clipChildren="false" + android:clipToOutline="false" + android:clipToPadding="false" android:divider="@drawable/volume_dialog_floating_sliders_spacer" android:gravity="bottom" android:orientation="horizontal" diff --git a/packages/SystemUI/res/layout/volume_dialog_slider.xml b/packages/SystemUI/res/layout/volume_dialog_slider.xml index 9ac456c17084..0acf4109bbb5 100644 --- a/packages/SystemUI/res/layout/volume_dialog_slider.xml +++ b/packages/SystemUI/res/layout/volume_dialog_slider.xml @@ -14,7 +14,6 @@ limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> @@ -24,11 +23,6 @@ android:layout_width="@dimen/volume_dialog_slider_width" android:layout_height="@dimen/volume_dialog_slider_height" android:layout_gravity="center" - android:theme="@style/Theme.Material3.Light" android:orientation="vertical" - app:thumbHeight="52dp" - app:trackCornerSize="12dp" - app:trackHeight="40dp" - app:trackStopIndicatorSize="6dp" - app:trackInsideCornerSize="2dp" /> + android:theme="@style/Theme.Material3.DayNight" /> </FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml index d850bbe63afd..cd8f18f7dcdb 100644 --- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml +++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml @@ -23,7 +23,6 @@ android:clipToPadding="false" android:gravity="center" android:layoutDirection="ltr" - android:orientation="vertical" app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene"> <!-- add ringer buttons here --> diff --git a/packages/SystemUI/res/raw/audio_bars_in.json b/packages/SystemUI/res/raw/audio_bars_in.json new file mode 100644 index 000000000000..c90a59c47d64 --- /dev/null +++ b/packages/SystemUI/res/raw/audio_bars_in.json @@ -0,0 +1 @@ +{"v":"5.7.13","fr":60,"ip":0,"op":18,"w":168,"h":168,"nm":"audio_bars_in","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":17,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":5,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/audio_bars_out.json b/packages/SystemUI/res/raw/audio_bars_out.json new file mode 100644 index 000000000000..5eab65e057ab --- /dev/null +++ b/packages/SystemUI/res/raw/audio_bars_out.json @@ -0,0 +1 @@ +{"v":"5.7.13","fr":60,"ip":0,"op":31,"w":168,"h":168,"nm":"audio_bars_out","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"t":30,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/audio_bars_playing.json b/packages/SystemUI/res/raw/audio_bars_playing.json new file mode 100644 index 000000000000..6ee8e1915f36 --- /dev/null +++ b/packages/SystemUI/res/raw/audio_bars_playing.json @@ -0,0 +1 @@ +{"v":"5.7.13","fr":60,"ip":0,"op":121,"w":168,"h":168,"nm":"audio_bars_playing","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[120.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":38,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[-0.016,-14.1],[5.941,-8.358],[5.961,0],[5.958,8.516],[0,14.274],[-5.958,8.515],[-5.961,0],[-5.972,-8.373]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":70,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":102,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[-0.016,-14.1],[5.941,-8.358],[5.961,0],[5.958,8.516],[0,14.274],[-5.958,8.515],[-5.961,0],[-5.972,-8.373]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-22.725],[5.957,-16.983],[5.961,0],[5.958,17.391],[0,23.149],[-5.958,17.39],[-5.961,0],[-5.957,-16.998]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[102.5,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":32,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-19.1],[5.957,-13.358],[5.961,0],[5.958,13.641],[0,19.399],[-5.958,13.64],[-5.961,0],[-5.957,-13.373]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":65,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":97,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-19.1],[5.957,-13.358],[5.961,0],[5.958,13.641],[0,19.399],[-5.958,13.64],[-5.961,0],[-5.957,-13.373]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-38.225],[5.957,-32.483],[5.961,0],[5.958,32.016],[0,37.774],[-5.958,32.015],[-5.961,0],[-5.957,-32.498]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.75,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-15.85],[5.957,-10.108],[5.961,0],[5.958,10.516],[0,16.274],[-5.958,10.515],[-5.961,0],[-5.957,-10.123]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":59,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":91,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-15.85],[5.957,-10.108],[5.961,0],[5.958,10.516],[0,16.274],[-5.958,10.515],[-5.961,0],[-5.957,-10.123]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-25.1],[5.957,-19.358],[5.961,0],[5.958,19.516],[0,25.274],[-5.958,19.515],[-5.961,0],[-5.957,-19.373]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-9.225],[5.957,-3.483],[5.961,0],[5.958,3.766],[0,9.524],[-5.958,3.765],[-5.961,0],[-5.957,-3.498]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":54,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":86,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-9.225],[5.957,-3.483],[5.961,0],[5.958,3.766],[0,9.524],[-5.958,3.765],[-5.961,0],[-5.957,-3.498]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-18.6],[5.957,-12.858],[5.961,0],[5.958,13.141],[0,18.899],[-5.958,13.14],[-5.961,0],[-5.957,-12.873]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[47.25,84,0],"ix":2,"l":2},"a":{"a":0,"k":[-37.161,0.089,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":48,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":81,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-5.961],[5.957,-0.219],[5.961,0],[5.958,0.203],[0,5.961],[-5.958,0.203],[-5.961,0],[-5.957,-0.235]],"c":true}]},{"t":120,"s":[{"i":[[-3.214,0],[-0.115,-3.191],[0,-0.073],[0.002,-0.067],[3.224,0],[0.107,3.198],[0,0.068],[-0.003,0.078]],"o":[[3.219,0],[0.003,0.073],[0,0.068],[-0.107,3.198],[-3.224,0],[-0.002,-0.067],[0,-0.079],[0.123,-3.184]],"v":[[0,-13.475],[5.957,-7.733],[5.961,0],[5.958,6.766],[0,12.524],[-5.958,6.765],[-5.961,0],[-5.957,-7.748]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-37.161,0.089],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":121,"st":0,"bm":0}],"markers":[{"tm":60,"cm":"1","dr":0}]}
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 1d0524a7192e..72b57cab8431 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Wys sluimerskermknoppie"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding is beskikbaar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliet-SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Noodoproepe of 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">"geen sein nie"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"een staaf"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"twee stawe"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"drie stawe"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"vier stawe"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sein is vol"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Pret vir party mense, maar nie vir almal nie"</string> <string name="tuner_warning" msgid="1861736288458481650">"Stelsel-UI-ontvanger gee jou ekstra maniere om die Android-gebruikerkoppelvlak in te stel en te pasmaak. Hierdie eksperimentele kenmerke kan in toekomstige uitreikings verander, breek of verdwyn. Gaan versigtig voort."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Verskaf bondelterugvoer"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Sluit skerm"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Maak ’n nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Verrigting van veelvuldige take"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gebruik verdeelde skerm met app aan die regterkant"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gebruik verdeelde skerm met app aan die linkerkant"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Skakel oor na volskerm"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skakel oor na app regs of onder terwyl jy verdeelde skerm gebruik"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skakel oor na app links of bo terwyl jy verdeelde skerm gebruik"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tydens verdeelde skerm: verplaas ’n app van een skerm na ’n ander"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/af-kieslys"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Sluitskerm"</string> - <string name="finder_active" msgid="7907846989716941952">"Jy kan hierdie foon met Kry My Toestel opspoor selfs wanneer dit afgeskakel is"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Sit tans af …"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sien versorgingstappe"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gaan na tuisskerm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Bekyk onlangse apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swiep links of regs met drie vingers op jou raakpaneel"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Mooi so!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Jy het die Gaan Terug-gebaar voltooi."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gaan na tuisskerm"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swiep op met drie vingers op jou raakpaneel"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Uitstekende werk!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Jy het die Gaan na Tuisskerm-gebaar voltooi"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Bekyk onlangse apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swiep op en hou met drie vingers op jou raakpaneel"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Knap gedaan!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jy het die Bekyk Onlangse Apps-gebaar voltooi."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Welgedaan!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jy het die Bekyk Onlangse Apps-gebaar voltooi"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutoriaalanimasie; klik om te onderbreek of hervat om te speel."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 687bd089d572..586c204e02da 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"የገፀ ማያ አሳራፊ አዝራርን አሳይ"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ሳተላይት፣ ግንኙነት አለ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ሳተላይት ኤስኦኤስ"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"የአደጋ ጥሪዎች ወይም ኤስኦኤስ"</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">"አንድ አሞሌ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ሁለት አሞሌዎች"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"ሦስት አሞሌዎች"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"አራት አሞሌዎች"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ምልክት ሙሉ ነው"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"የስራ መገለጫ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ለአንዳንዶች አስደሳች ቢሆንም ለሁሉም አይደለም"</string> <string name="tuner_warning" msgid="1861736288458481650">"የስርዓት በይነገጽ መቃኛ የAndroid ተጠቃሚ በይነገጹን የሚነካኩበት እና የሚያበጁበት ተጨማሪ መንገዶች ይሰጠዎታል። እነዚህ የሙከራ ባህሪዎች ወደፊት በሚኖሩ ልቀቶች ላይ ሊለወጡ፣ ሊሰበሩ ወይም ሊጠፉ ይችላሉ። ከጥንቃቄ ጋር ወደፊት ይቀጥሉ።"</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"የቅርቅብ ግብረመልስ አቅርብ"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"መተግበሪያ በስተቀኝ ላይ ሆኖ የተከፈለ ማያ ገፅን ይጠቀሙ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"መተግበሪያ በስተግራ ላይ ሆኖ የተከፈለ ማያ ገፅን ይጠቀሙ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ወደ ሙሉ ገፅ ዕይታ ይቀይሩ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከታች ወዳለ መተግበሪያ ይቀይሩ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከላይ ወዳለ መተግበሪያ ይቀይሩ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"በተከፈለ ማያ ገጽ ወቅት፡- መተግበሪያን ከአንዱ ወደ ሌላው ተካ"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"የኃይል ምናሌ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ገፅ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ማያ ገፅ ቁልፍ"</string> - <string name="finder_active" msgid="7907846989716941952">"ይህ መሣሪያ ኃይል ጠፍቶ ቢሆንም እንኳን በየእኔን መሣሪያ አግኝ ማግኘት ይችላሉ"</string> <string name="shutdown_progress" msgid="5464239146561542178">"በመዝጋት ላይ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ወደ መነሻ ሂድ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"የቅርብ ጊዜ መተግበሪያዎችን አሳይ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ተከናውኗል"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ወደኋላ ተመለስ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደ ግራ ወይም ወደ ቀኝ ያንሸራትቱ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"አሪፍ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ወደኋላ የመመለስ ምልክትን አጠናቅቀዋል።"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ወደ መነሻ ሂድ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"በመዳሰሻ ሰሌዳዎ ላይ በሦስት ጣቶች ወደ ላይ ያንሸራትቱ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ጥሩ ሥራ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ወደ መነሻ ሂድ ምልክትን አጠናቅቀዋል"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"የቅርብ ጊዜ መተግበሪያዎችን አሳይ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደላይ ያንሸራትቱ እና ይያዙ"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ጥሩ ሠርተዋል!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"የቅርብ ጊዜ መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል።"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"የሁሉንም መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 0fc6598d404d..92d0cbb823bc 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -592,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"الإشعارات"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"محو جميع الإشعارات الصامتة"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"يؤدي النقر على هذا الزر إلى فتح إعدادات الإشعارات"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"تم إيقاف الإشعارات مؤقتًا وفقًا لإعداد \"عدم الإزعاج\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ما مِن إشعارات}=1{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\"}=2{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" ووضع واحد آخر}few{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# أوضاع أخرى}many{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضعًا آخر}other{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضع آخر}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"البدء الآن"</string> @@ -754,6 +753,20 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"قمر صناعي، الاتصال متوفّر"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"اتصالات الطوارئ بالقمر الصناعي"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"مكالمات الطوارئ أو ميزة \"اتصالات طوارئ بالقمر الصناعي\""</string> + <!-- no translation found for accessibility_phone_string_format (7798841417881811812) --> + <skip /> + <!-- no translation found for accessibility_no_signal (7052827511409250167) --> + <skip /> + <!-- no translation found for accessibility_one_bar (5342012847647834506) --> + <skip /> + <!-- no translation found for accessibility_two_bars (122628483354508429) --> + <skip /> + <!-- no translation found for accessibility_three_bars (5143286602926069024) --> + <skip /> + <!-- no translation found for accessibility_four_bars (8838495563822541844) --> + <skip /> + <!-- no translation found for accessibility_signal_full (1519655809806462972) --> + <skip /> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ملف العمل"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"متعة للبعض وليس للجميع"</string> <string name="tuner_warning" msgid="1861736288458481650">"توفر لك أداة ضبط واجهة مستخدم النظام طرقًا إضافية لتعديل واجهة مستخدم Android وتخصيصها. ويمكن أن تطرأ تغييرات على هذه الميزات التجريبية أو يمكن أن تتعطل هذه الميزات أو تختفي في الإصدارات المستقبلية. عليك متابعة الاستخدام مع توخي الحذر."</string> @@ -787,7 +800,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"تقديم ملاحظات مُجمّعة"</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> @@ -873,12 +885,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليمين"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليسار"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"التبديل إلى وضع ملء الشاشة"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"التبديل إلى التطبيق على اليسار أو الأسفل أثناء استخدام \"تقسيم الشاشة\""</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"التبديل إلى التطبيق على اليمين أو الأعلى أثناء استخدام \"تقسيم الشاشة\""</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"استبدال تطبيق بآخر في وضع \"تقسيم الشاشة\""</string> @@ -980,7 +989,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"قائمة زر التشغيل"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"شاشة القفل"</string> - <string name="finder_active" msgid="7907846989716941952">"يمكنك تحديد مكان هذا الهاتف باستخدام تطبيق \"العثور على جهازي\" حتى عندما يكون مُطفئًا."</string> <string name="shutdown_progress" msgid="5464239146561542178">"جارٍ إيقاف التشغيل…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"الاطّلاع على خطوات العناية"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string> @@ -1467,22 +1475,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"الانتقال إلى الصفحة الرئيسية"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"عرض التطبيقات المستخدَمة مؤخرًا"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تم"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"مرِّر سريعًا لليمين أو لليسار باستخدام 3 أصابع على لوحة اللمس"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"أحسنت."</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"لقد أكملت التدريب على إيماءة الرجوع."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"الانتقال إلى الشاشة الرئيسية"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"مرّر سريعًا للأعلى باستخدام 3 أصابع على لوحة اللمس"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"أحسنت صنعًا."</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"لقد أكملت الدليل التوجيهي عن إيماءة \"الانتقال إلى الشاشة الرئيسية\""</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"عرض التطبيقات المستخدَمة مؤخرًا"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"مرِّر سريعًا للأعلى مع الاستمرار باستخدام 3 أصابع على لوحة اللمس"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"أحسنت."</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت التدريب على إيماءة عرض التطبيقات المستخدَمة مؤخرًا."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"لقد أكملْت التدريب على إيماءة عرض جميع التطبيقات"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index b0a9d0960087..89e5083fdc23 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"জৰুৰীকালীন কল বা 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">"এডাল দণ্ড"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"দুডাল দণ্ড"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"তিনিডাল দণ্ড"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"চাৰিডাল দণ্ড"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"সম্পূৰ্ণ ছিগনেল"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"কিছুমানৰ বাবে আমোদজনক হয় কিন্তু সকলোৰে বাবে নহয়"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tunerএ আপোনাক Android ব্যৱহাৰকাৰী ইণ্টাৰফেইচ সলনি কৰিবলৈ আৰু নিজৰ উপযোগিতা অনুসৰি ব্যৱহাৰ কৰিবলৈ অতিৰিক্ত সুবিধা প্ৰদান কৰে। এই পৰীক্ষামূলক সুবিধাসমূহ সলনি হ\'ব পাৰে, সেইবোৰে কাম নকৰিব পাৰে বা আগন্তুক সংস্কৰণসমূহত সেইবোৰ অন্তৰ্ভুক্ত কৰা নহ’ব পাৰে। সাৱধানেৰে আগবাঢ়ক।"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"বাণ্ডল হিচাপে থকা জাননীত মতামত প্ৰদান কৰক"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"সোঁফালে থকা এপ্টোৰ সৈতে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"বাওঁফালে থকা এপ্টোৰ সৈতে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"পূৰ্ণ স্ক্ৰীনলৈ সলনি কৰক"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত সোঁফালে অথবা তলত থকা এপলৈ সলনি কৰক"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত বাওঁফালে অথবা ওপৰত থকা এপলৈ সলনি কৰক"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"বিভাজিত স্ক্ৰীনৰ ব্যৱহাৰ কৰাৰ সময়ত: কোনো এপ্ এখন স্ক্ৰীনৰ পৰা আনখনলৈ নিয়ক"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাৱাৰ মেনু"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্ৰীন"</string> - <string name="finder_active" msgid="7907846989716941952">"পাৱাৰ অফ কৰা থাকিলেও Find My Deviceৰ জৰিয়তে আপুনি এই ফ’নটোৰ অৱস্থান নিৰ্ধাৰণ কৰিব পাৰে"</string> <string name="shutdown_progress" msgid="5464239146561542178">"বন্ধ কৰি থকা হৈছে…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"গৃহ পৃষ্ঠালৈ যাওক"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"শেহতীয়া এপ্সমূহ চাওক"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হ’ল"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁফাললৈ বা সোঁফাললৈ ছোৱাইপ কৰক"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"সুন্দৰ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"আপুনি উভতি যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"গৃহ পৃষ্ঠালৈ যাওক"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলিৰে ওপৰলৈ ছোৱাইপ কৰক"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"বঢ়িয়া!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"আপুনি গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"শেহতীয়া এপ্সমূহ চাওক"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"বঢ়িয়া!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"আপুনি শেহতীয়া এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে।"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"আপুনি আটাইবোৰ এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$dৰ %1$d স্তৰ"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 0f59bfbc86df..31238d0e0c41 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran qoruyucu düyməsini göstərin"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Peyk, bağlantı var"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Təcili peyk bağlantısı"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Təcili zənglər və ya 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">"siqnal yoxdur"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"bir zolaq"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"iki zolaq"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"üç zolaq"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"dörd zolaq"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"siqnal tamdır"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Hamı üçün deyil, bəziləri üçün əyləncəli"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner Android istifadəçi interfeysini dəyişdirmək və fərdiləşdirmək üçün Sizə ekstra yollar təklif edir."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Paket rəyi təmin edin"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Kilid ekranı"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Qeyd götürün"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Çoxsaylı tapşırıq icrası"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Tətbiq sağda olmaqla bölünmüş ekranı istifadə edin"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Tətbiq solda olmaqla bölünmüş ekranı istifadə edin"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Tam ekran rejiminə keçin"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran istifadə edərkən sağda və ya aşağıda tətbiqə keçin"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran istifadə edərkən solda və ya yuxarıda tətbiqə keçin"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran rejimində: tətbiqi birindən digərinə dəyişin"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Qidalanma düyməsi menyusu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran kilidi"</string> - <string name="finder_active" msgid="7907846989716941952">"Bu telefon sönülü olsa belə, Cihazın Tapılması ilə onu tapa bilərsiniz"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Söndürülür…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ehtiyat tədbiri mərhələlərinə baxın"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Əsas səhifəyə keçin"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son tətbiqlərə baxın"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hazırdır"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Taçpeddə üç barmaqla sola və ya sağa sürüşdürün"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Əla!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Geri getmə jestini tamamladınız."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Əsas səhifəyə keçin"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Taçpeddə üç barmaqla yuxarı sürüşdürün"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Əla!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Əsas səhifəyə keçid jestini tamamladınız"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Son tətbiqlərə baxın"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Taçpeddə üç barmaqla yuxarı çəkib saxlayın"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Əla!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son tətbiqlərə baxmaq jestini tamamladınız."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Əla!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\"Bütün tətbiqlərə baxın\" jestini tamamladınız"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Öyrədici animasiya, oxudulmanı durdurmaq və davam etdirmək üçün klikləyin."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index a339b114f798..68100187e717 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć preko satelita"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili hitna pomoć"</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">"nema signala"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crta"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dve crte"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tri crte"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"četiri crte"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal je najjači"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string> <string name="tuner_warning" msgid="1861736288458481650">"Tjuner za korisnički interfejs sistema vam pruža dodatne načine za podešavanje i prilagođavanje Android korisničkog interfejsa. Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Pružite povratne informacije o skupu"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Otključavanje ekrana"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Napravi belešku"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Obavljanje više zadataka istovremeno"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Koristi podeljeni ekran sa aplikacijom s desne strane"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Koristi podeljeni ekran sa aplikacijom s leve strane"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Pređi na režim preko celog ekrana"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pređi u aplikaciju zdesna ili ispod dok je podeljen ekran"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju sleva ili iznad dok koristite podeljeni ekran"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"U režimu podeljenog ekrana: zamena jedne aplikacije drugom"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni dugmeta za uključivanje"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključan ekran"</string> - <string name="finder_active" msgid="7907846989716941952">"Možete da locirate ovaj telefon pomoću usluge Pronađi moj uređaj čak i kada je isključen"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Isključuje se…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte upozorenja"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Idi na početni ekran"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavno korišćene aplikacije"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prevucite ulevo ili udesno sa tri prsta na tačpedu"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Super!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Dovršili ste pokret za povratak."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Idi na početni ekran"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prevucite nagore sa tri prsta na tačpedu"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Odlično!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Dovršili ste pokret za povratak na početnu stranicu."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Prikaži nedavno korišćene aplikacije"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prevucite nagore i zadržite sa tri prsta na tačpedu"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dovršili ste pokret za prikazivanje nedavno korišćenih aplikacija."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dovršili ste pokret za prikazivanje svih aplikacija."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacija vodiča, kliknite da biste pauzirali i nastavili reprodukciju."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 9c5a4f287137..d95fd67c5dad 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Паказаць застаўку\""</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спадарожнікавая сувязь, падключэнне даступнае"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Экстраннае спадарожнікавае падключэнне"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Экстранныя выклікі або экстраннае спадарожнікавае падключэнне"</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">"адзiн слупок"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"два слупкi"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"тры слупкi"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"чатыры слупкі"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"сігнал поўны"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Працоўны профіль"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Цікава для некаторых, але не для ўсіх"</string> <string name="tuner_warning" msgid="1861736288458481650">"Наладка сістэмнага інтэрфейсу карыстальніка дае вам дадатковыя спосабы наладжвання і дапасоўвання карыстальніцкага інтэрфейсу Android. Гэтыя эксперыментальныя функцыі могуць змяніцца, перастаць працаваць або знікнуць у будучых версіях. Карыстайцеся з асцярожнасцю."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Пакінуць групавы водгук"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Падзяліць экран і памясціць праграму справа"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Падзяліць экран і памясціць праграму злева"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Уключыць поўнаэкранны рэжым"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пераключыцца на праграму справа або ўнізе на падзеленым экране"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пераключыцца на праграму злева або ўверсе на падзеленым экране"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"У рэжыме падзеленага экрана замяніць адну праграму на іншую"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопкі сілкавання"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Экран блакіроўкі"</string> - <string name="finder_active" msgid="7907846989716941952">"Вы можаце знайсці свой тэлефон з дапамогай праграмы \"Знайсці прыладу\", нават калі ён выключаны"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Ідзе завяршэнне працы…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Глядзець паэтапную дапамогу"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На галоўную старонку"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прагляд нядаўніх праграм"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Гатова"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўлева ці ўправа"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Выдатна!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Вы навучыліся рабіць жэст вяртання."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"На галоўны экран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўверх"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Выдатная праца!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Вы навучыліся рабіць жэст для пераходу на галоўны экран"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прагляд нядаўніх праграм"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Правядзіце па сэнсарнай панэлі трыма пальцамі ўверх і затрымайце пальцы"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Выдатная праца!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы скончылі вывучэнне жэсту для прагляду нядаўніх праграм."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы навучыліся рабіць жэст для прагляду ўсіх праграм"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index ac2edfe1fc61..344c011e74d4 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"Спешни обаждания или 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">"една чертичка"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"две чертички"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"три чертички"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"четири чертички"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"сигналът е пълен"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Потребителски профил в Work"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Забавно – но не за всички"</string> <string name="tuner_warning" msgid="1861736288458481650">"Тунерът на системния потребителски интерфейс ви предоставя допълнителни възможности за прецизиране и персонализиране на практическата работа с Android. Тези експериментални функции може да се променят, повредят или да изчезнат в бъдещите версии. Действайте внимателно."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Предоставяне на отзиви за пакета"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Използване на разделен екран с приложението вдясно"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Използване на разделен екран с приложението вляво"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Превключване на цял екран"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Превключване към приложението вдясно/отдолу в режима на разделен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Превключване към приложението вляво/отгоре в режима на разделен екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"При разделен екран: замяна на дадено приложение с друго"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню за включване/изключване"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Заключен екран"</string> - <string name="finder_active" msgid="7907846989716941952">"Можете да откриете този телефон посредством „Намиране на устройството ми“ дори когато е изключен"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Изключва се…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Вижте стъпките, които да предприемете"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Към началния екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Преглед на скорошните приложения"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Плъзнете три пръста наляво или надясно по сензорния панел"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Чудесно!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Изпълнихте жеста за връщане назад."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Към началния екран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Плъзнете три пръста нагоре по сензорния панел"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Отлично!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Изпълнихте жеста за преминаване към началния екран"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Преглед на скорошните приложения"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Плъзнете три пръста нагоре по сензорния панел и задръжте"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Изпълнихте жеста за преглед на скорошните приложения."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Изпълнихте жеста за преглед на всички приложения"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index c35c62aec312..d7b24c8fe2ee 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"স্ক্রিন সেভার বোতাম দেখুন"</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> @@ -701,7 +700,7 @@ <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string> <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string> <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string> - <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"আশপাশের আওয়াজ কন্ট্রোল করা"</string> + <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"নয়েজ কন্ট্রোল"</string> <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"স্পেশিয়ল অডিও"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"বন্ধ আছে"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"চালু আছে"</string> @@ -754,6 +753,13 @@ <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="828510231597991206">"জরুরি কল বা 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">"একটি বার"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"দুটি বার"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"তিনটি বার"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"চারটি বার"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"সম্পূর্ণ সিগন্যাল"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"কাজের প্রোফাইল"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"কিছু ব্যক্তির জন্য মজাদার কিন্তু সকলের জন্য নয়"</string> <string name="tuner_warning" msgid="1861736288458481650">"এই পরীক্ষামূলক বৈশিষ্ট্যগুলি ভবিষ্যতের সংস্করণগুলির মধ্যে পরিবর্তিত, বিভাজিত এবং অদৃশ্য হয়ে যেতে পারে৷ সাবধানতার সাথে এগিয়ে যান৷ সিস্টেম UI টিউনার আপনাকে Android ব্যবহারকারী ইন্টারফেসের সূক্ষ্ম সমন্বয় এবং কাস্টমাইজ করার অতিরিক্ত উপায়গুলি প্রদান করে৷"</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"বান্ডেল সম্পর্কে মতামত দিন"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ডানদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"বাঁদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ফুল-স্ক্রিন মোডে সুইচ করুন"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"স্প্লিট স্ক্রিন ব্যবহার করার সময় ডানদিকের বা নিচের অ্যাপে পাল্টে নিন"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"স্প্লিট স্ক্রিন ব্যবহার করার সময় বাঁদিকের বা উপরের অ্যাপে পাল্টে নিন"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"\'স্প্লিট স্ক্রিন\' থাকাকালীন: একটি অ্যাপ থেকে অন্যটিতে পাল্টান"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাওয়ার মেনু"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্রিন"</string> - <string name="finder_active" msgid="7907846989716941952">"Find My Device-এর মাধ্যমে, ফোনটি বন্ধ করা থাকলেও এটির লোকেশন শনাক্ত করতে পারবেন"</string> <string name="shutdown_progress" msgid="5464239146561542178">"বন্ধ হচ্ছে…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"হোমে যান"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হয়ে গেছে"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"আপনার টাচপ্যাডে তিনটি আঙুল ব্যবহার করে বাঁদিকে বা ডানদিকে সোয়াইপ করুন"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"সাবাস!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"জেসচার ব্যবহার করে কীভাবে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন।"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"হোমে যান"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"আপনার টাচপ্যাডে তিনটি আঙুলের সাহায্যে উপরের দিকে সোয়াইপ করুন"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"অসাধারণ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"জেসচার ব্যবহার করে কীভাবে হোমে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"আপনার টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"অসাধারণ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপের জেসচার দেখা সম্পূর্ণ করেছেন।"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"আপনি \'সব অ্যাপের জেসচার দেখুন\' টিউটোরিয়াল সম্পূর্ণ করেছেন"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d-এর মধ্যে %1$d লেভেল"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index f842aabe4514..b85845940204 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -531,7 +531,7 @@ <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">"Prikaži gumb čuvara zaslona"</string> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Dugme za prikaz čuvara ekrana"</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> @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć putem satelita"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili pomoć"</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">"nema signala"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dvije crtice"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tri crtice"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"četiri crtice"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"pun signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Radni profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string> <string name="tuner_warning" msgid="1861736288458481650">"Podešavač za korisnički interfejs sistema vam omogućava dodatne načine da podesite i prilagodite Androidov interfejs. Ove eksperimentalne funkcije se u budućim verzijama mogu mijenjati, kvariti ili nestati. Budite oprezni."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Pošaljite povratne informacije o paketu"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaključavanje ekrana"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Pisanje bilješke"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Korištenje podijeljenog ekrana s aplikacijom na desnoj strani"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Korištenje podijeljenog ekrana s aplikacijom na lijevoj strani"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Prelazak na prikaz preko cijelog ekrana"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak u aplikaciju desno ili ispod uz podijeljeni ekran"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju lijevo ili iznad dok koristite podijeljeni ekran"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Za vrijeme podijeljenog ekrana: zamjena jedne aplikacije drugom"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni napajanja"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani ekran"</string> - <string name="finder_active" msgid="7907846989716941952">"Možete pronaći telefon putem usluge Pronađi moj uređaj čak i kada je isključen"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Isključivanje…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte korake za zaštitu"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string> @@ -1434,7 +1436,7 @@ <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da dodijelite prečicu"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ovo će trajno izbrisati prilagođenu prečicu."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ovo će trajno izbrisati sve vaše prilagođene prečice."</string> - <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string> + <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tipke radnji ili meta tipka"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Odlazak na početni ekran"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavne aplikacije"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prevucite ulijevo ili udesno s tri prsta na dodirnoj podlozi"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Lijepo!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Savladali ste pokret za vraćanje."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Odlazak na početni ekran"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prevucite nagore s tri prsta na dodirnoj podlozi"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Sjajno!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Savladali ste pokret za odlazak na početni ekran"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Prikaz nedavnih aplikacija"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prevucite nagore i zadržite s tri prsta na dodirnoj podlozi"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavnih aplikacija."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvršili ste pokret za prikaz svih aplikacija"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacija vodiča; pauziranje i nastavak reprodukcije klikom."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 3386dc0775ca..c8f371cff8d3 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satèl·lit, connexió disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS per satèl·lit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Trucades d\'emergència o 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">"no hi ha senyal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dues barres"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tres barres"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"quatre barres"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"senyal complet"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de treball"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversió per a uns quants, però no per a tothom"</string> <string name="tuner_warning" msgid="1861736288458481650">"El Personalitzador d\'interfície d\'usuari presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Proporciona suggeriments sobre el paquet"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloqueja la pantalla"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Crea una nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasca"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utilitzar la pantalla dividida amb l\'aplicació a la dreta"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utilitzar la pantalla dividida amb l\'aplicació a l\'esquerra"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Canviar a pantalla completa"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Canvia a l\'aplicació de la dreta o de sota amb la pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Canvia a l\'aplicació de l\'esquerra o de dalt amb la pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durant el mode de pantalla dividida: substitueix una app per una altra"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú d\'engegada"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueig"</string> - <string name="finder_active" msgid="7907846989716941952">"Pots localitzar aquest telèfon amb Troba el meu dispositiu fins i tot quan estigui apagat"</string> <string name="shutdown_progress" msgid="5464239146561542178">"S\'està apagant…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Mostra els passos de manteniment"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ves a la pantalla d\'inici"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Mostra les aplicacions recents"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fet"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Llisca cap a l\'esquerra o cap a la dreta amb tres dits al ratolí tàctil"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Molt bé!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Has completat el gest per tornar enrere."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ves a la pantalla d\'inici"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Llisca cap amunt amb tres dits al ratolí tàctil"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ben fet!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Has completat el gest per anar a la pantalla d\'inici"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Mostra les aplicacions recents"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Llisca cap amunt amb tres dits i mantén-los premuts al ratolí tàctil"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ben fet!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Enhorabona!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Has completat el gest per veure totes les aplicacions"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animació del tutorial; fes clic per posar en pausa i reprendre la reproducció."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index c5aea85af4c7..efc699b09317 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, připojení je k dispozici"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS přes satelit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Tísňová volání nebo 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">"není signál"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čárka"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dvě čárky"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tři čárky"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"čtyři čárky"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"plný signál"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovní profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zábava, která není pro každého"</string> <string name="tuner_warning" msgid="1861736288458481650">"Nástroj na ladění uživatelského rozhraní systému vám nabízí další způsoby, jak si vyladit a přizpůsobit uživatelské rozhraní Android. Tyto experimentální funkce mohou v dalších verzích chybět, nefungovat nebo být změněny. Postupujte proto prosím opatrně."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Zpětná vazba k balíčku"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknout obrazovku"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Vytvořit poznámku"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Použít rozdělenou obrazovku s aplikací vpravo"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Použít rozdělenou obrazovku s aplikací vlevo"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Přepnout na celou obrazovku"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Přepnout na aplikaci vpravo nebo dole v režimu rozdělené obrazovky"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Přepnout na aplikaci vlevo nebo nahoře v režimu rozdělené obrazovky"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"V režimu rozdělené obrazovky: nahradit jednu aplikaci druhou"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Nabídka vypínače"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Obrazovka uzamčení"</string> - <string name="finder_active" msgid="7907846989716941952">"Tento telefon můžete pomocí funkce Najdi moje zařízení najít, i když je vypnutý"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Vypínání…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobrazit pokyny, co dělat"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Přejít na domovskou stránku"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazit nedávné aplikace"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Přejeďte po touchpadu třemi prsty doleva nebo doprava"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Skvělé!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Provedli jste gesto pro přechod zpět."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Přejít na plochu"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Přejeďte po touchpadu třemi prsty nahoru"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Výborně!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Provedli jste gesto pro přechod na plochu"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Zobrazit nedávné aplikace"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Přejeďte po touchpadu třemi prsty nahoru a podržte je"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Výborně!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Provedli jste gesto pro zobrazení nedávných aplikací."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Provedli jste gesto k zobrazení všech aplikací"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Výuková animace, kliknutím pozastavíte nebo obnovíte."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 168afad1817c..4336a853b33f 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Knappen Vis pauseskærm"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit – forbindelsen er tilgængelig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-meldinger via satellit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nødopkald eller SOS-meldinger via satellit"</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">"intet signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"én bjælke"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"to bjælker"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tre bjælker"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"fire bjælker"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"fuldt signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbejdsprofil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Sjovt for nogle, men ikke for alle"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner giver dig flere muligheder for at justere og tilpasse Android-brugerfladen. Disse eksperimentelle funktioner kan ændres, gå i stykker eller forsvinde i fremtidige udgivelser. Vær forsigtig, hvis du fortsætter."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Giv feedback om pakker"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skærm"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Skriv en note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Brug opdelt skærm med appen til højre"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Brug opdelt skærm med appen til venstre"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Skift til fuld skærm"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skift til en app til højre eller nedenfor, når du bruger opdelt skærm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skift til en app til venstre eller ovenfor, når du bruger opdelt skærm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ved opdelt skærm: Udskift én app med en anden"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu for afbryderknappen"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskærm"</string> - <string name="finder_active" msgid="7907846989716941952">"Du kan finde denne telefon med Find min enhed, også selvom den er slukket"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Lukker ned…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se håndteringsvejledning"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se seneste apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Udfør"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Stryg til venstre eller højre med tre fingre på touchpladen"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sådan!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du har udført bevægelsen for Gå tilbage."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gå til startskærmen"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Stryg opad med tre fingre på touchpladen"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Flot!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du har udført bevægelsen for at gå til startsiden"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se seneste apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Stryg opad, og hold tre fingre på touchpladen"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Godt klaret!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har udført bevægelsen for at se de seneste apps."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Flot klaret!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har udført bevægelsen for at se alle apps"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation med vejledning. Klik for at sætte afspilningen på pause og genoptage den."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index bf323ddbb2f6..6e8cffee3b03 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Schaltfläche „Bildschirmschoner anzeigen“"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, Verbindung verfügbar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Notruf über Satellit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Notrufe oder 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">"kein Empfang"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"ein Balken"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"zwei Balken"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"drei Balken"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"vier Balken"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"volle Signalstärke"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Arbeitsprofil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Für einige ein Vergnügen, aber nicht für alle"</string> <string name="tuner_warning" msgid="1861736288458481650">"Mit System UI Tuner erhältst du zusätzliche Möglichkeiten, die Android-Benutzeroberfläche anzupassen. Achtung: Diese Testfunktionen können sich ändern, abstürzen oder in zukünftigen Versionen verschwinden."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Feedback zu gebündelten Nachrichten geben"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Bildschirm sperren"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Notiz machen"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Splitscreen mit der App auf der rechten Seite nutzen"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Splitscreen mit der App auf der linken Seite nutzen"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"In den Vollbildmodus wechseln"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Im Splitscreen-Modus zu einer App rechts oder unten wechseln"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Im Splitscreen-Modus zu einer App links oder oben wechseln"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Im Splitscreen: eine App durch eine andere ersetzen"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ein-/Aus-Menü"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Sperrbildschirm"</string> - <string name="finder_active" msgid="7907846989716941952">"Du kannst dieses Smartphone über „Mein Gerät finden“ orten, auch wenn es ausgeschaltet ist"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Wird heruntergefahren…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Schritte zur Abkühlung des Geräts ansehen"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Schritte zur Abkühlung des Geräts ansehen"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Zum Startbildschirm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Letzte Apps aufrufen"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fertig"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Wische mit drei Fingern auf dem Touchpad nach links oder rechts"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sehr gut!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du hast das Tutorial für die „Zurück“-Touch-Geste abgeschlossen."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Startbildschirm"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Wische an einer beliebigen Stelle auf dem Touchpad mit drei Fingern nach oben"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Gut gemacht!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du hast den Schritt für die „Startbildschirm“-Touch-Geste abgeschlossen"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Letzte Apps aufrufen"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Wische mit drei Fingern nach oben und halte das Touchpad gedrückt"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Gut gemacht!"</string> <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> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Perfekt!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du hast das Tutorial für die Touch-Geste zum Aufrufen aller Apps abgeschlossen"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation während des Tutorials, zum Pausieren und Fortsetzen der Wiedergabe klicken."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index a90f70122a2c..21822202c11d 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"Κλήσεις έκτακτης ανάγκης ή 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">"μία γραμμή"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"δύο γραμμές"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"τρεις γραμμές"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"τέσσερις γραμμές"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"πλήρες σήμα"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Προφίλ εργασίας"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Διασκέδαση για ορισμένους, αλλά όχι για όλους"</string> <string name="tuner_warning" msgid="1861736288458481650">"Το System UI Tuner σάς προσφέρει επιπλέον τρόπους για να τροποποιήσετε και να προσαρμόσετε τη διεπαφή χρήστη Android. Αυτές οι πειραματικές λειτουργίες ενδέχεται να τροποποιηθούν, να παρουσιάσουν σφάλματα ή να καταργηθούν σε μελλοντικές εκδόσεις. Συνεχίστε με προσοχή."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Παροχή σχολίων για πακέτο"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Χρήση διαχωρισμού οθόνης με την εφαρμογή στα δεξιά"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Χρήση διαχωρισμού οθόνης με την εφαρμογή στα αριστερά"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Εναλλαγή σε πλήρη οθόνη"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Εναλλαγή στην εφαρμογή δεξιά ή κάτω κατά τη χρήση διαχωρισμού οθόνης"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Εναλλαγή σε εφαρμογή αριστερά ή επάνω κατά τη χρήση διαχωρισμού οθόνης"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Κατά τον διαχωρισμό οθόνης: αντικατάσταση μιας εφαρμογής με άλλη"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Μενού λειτουργίας"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Οθόνη κλειδώματος"</string> - <string name="finder_active" msgid="7907846989716941952">"Μπορείτε να εντοπίσετε το συγκεκριμένο τηλέφωνο με την Εύρεση συσκευής ακόμα και όταν είναι απενεργοποιημένο"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Τερματισμός λειτουργίας…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Δείτε βήματα αντιμετώπισης."</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Αρχική"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Προβολή πρόσφατων εφαρμογών"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Τέλος"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Επιστροφή"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Σύρετε προς τα αριστερά ή τα δεξιά με τρία δάχτυλα στην επιφάνεια αφής"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Ωραία!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ολοκληρώσατε την κίνηση επιστροφής."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Αρχική"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Σύρετε προς τα επάνω με τρία δάχτυλα στην επιφάνεια αφής"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Μπράβο!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Προβολή πρόσφατων εφαρμογών"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Σύρετε προς τα επάνω με τρία δάχτυλα στην επιφάνεια αφής και μην τα σηκώσετε"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Μπράβο!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ολοκληρώσατε την κίνηση για την προβολή πρόσφατων εφαρμογών."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ολοκληρώσατε την κίνηση για την προβολή όλων των εφαρμογών"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 679684a31ee7..779e3f684898 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or 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">"No signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"two bars"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"three bars"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"four bars"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal full"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Provide bundle feedback"</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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Switch to full screen"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string> - <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animation, click to pause and resume play."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index f54745dfc3a5..22916c337b97 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or 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">"no signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"two bars"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"three bars"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"four bars"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal full"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customize the Android user interface. These experimental features may change, break, or disappear in future releases. Proceed with caution."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Provide Bundle Feedback"</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> @@ -976,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string> - <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string> @@ -1463,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> + <string name="gesture_error_title" msgid="469064941635578511">"Try again!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"To go back using your touchpad, swipe left or right using three fingers"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Great job!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"Swipe up with three fingers on your touchpad to go to your home screen"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Great job!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> + <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"Press the action key on your keyboard to view all of your apps"</string> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animation, click to pause and resume play."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 679684a31ee7..779e3f684898 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or 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">"No signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"two bars"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"three bars"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"four bars"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal full"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Provide bundle feedback"</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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Switch to full screen"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string> - <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animation, click to pause and resume play."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 679684a31ee7..779e3f684898 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Emergency calls or 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">"No signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"two bars"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"three bars"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"four bars"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal full"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work profile"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Fun for some but not for all"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner gives you extra ways to tweak and customise the Android user interface. These experimental features may change, break or disappear in future releases. Proceed with caution."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Provide bundle feedback"</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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use split screen with app on the right"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use split screen with app on the left"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Switch to full screen"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"During split screen: Replace an app from one to another"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string> - <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe left or right using three fingers on your touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Nice!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"You completed the go back gesture."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Go home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe up with three fingers on your touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Well done!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"You completed the go home gesture"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animation, click to pause and resume play."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index ca53976cd3fb..1f3aee8f6496 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Llamadas de emergencia o 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">"sin señal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dos barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tres barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"cuatro barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"señal completa"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversión solo para algunas personas"</string> <string name="tuner_warning" msgid="1861736288458481650">"El sintonizador de IU del sistema te brinda más formas para editar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, dejar de funcionar o no incluirse en futuras versiones. Procede con precaución."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Proporcionar comentarios sobre el conjunto"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloquear la pantalla"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Crear una nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Tareas múltiples"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar la pantalla dividida con la app a la derecha"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar la pantalla dividida con la app a la izquierda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Cambiar a pantalla completa"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ubicar la app a la derecha o abajo cuando usas la pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ubicar la app a la izquierda o arriba cuando usas la pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante pantalla dividida: Reemplaza una app con otra"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string> - <string name="finder_active" msgid="7907846989716941952">"Puedes ubicar este teléfono con Encontrar mi dispositivo, incluso si está apagado"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Apagando…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir a la página principal"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recientes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Listo"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Desliza hacia la izquierda o la derecha con tres dedos en el panel táctil"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"¡Muy bien!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Completaste el gesto para ir atrás."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir a la página principal"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Desliza hacia arriba con tres dedos en el panel táctil"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"¡Bien hecho!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Completaste el gesto para ir a la página principal"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver apps recientes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Desliza hacia arriba con tres dedos en el panel táctil y mantenlos presionados"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaste el gesto para ver las apps recientes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Bien hecho!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Completaste el gesto para ver todas las apps"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animación del instructivo. Haz clic para pausar y reanudar la reproducción."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 28812cca3c43..8ae684a0c859 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botón para mostrar el salvapantallas"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Llamadas de emergencia o 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">"no hay señal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dos barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tres barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"cuatro barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"señal al máximo"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversión solo para algunos"</string> <string name="tuner_warning" msgid="1861736288458481650">"El configurador de UI del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar comentarios sobre el paquete"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Escribir una nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarea"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar la pantalla dividida con la aplicación a la derecha"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar la pantalla dividida con la aplicación a la izquierda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Cambiar a pantalla completa"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar a la aplicación de la derecha o de abajo en pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar a la app de la izquierda o de arriba en pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Con pantalla dividida: reemplazar una aplicación por otra"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string> - <string name="finder_active" msgid="7907846989716941952">"Puedes localizar este teléfono con Encontrar mi dispositivo, aunque esté apagado"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Apagando…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir a Inicio"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver aplicaciones recientes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hecho"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Desliza hacia la izquierda o la derecha con tres dedos en el panel táctil"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"¡Genial!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Has completado el gesto para volver."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir a Inicio"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Desliza hacia arriba con tres dedos en el panel táctil"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"¡Bien hecho!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Has completado el gesto para ir a la pantalla de inicio"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver aplicaciones recientes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Desliza hacia arriba con tres dedos y mantén pulsado en el panel táctil"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completado el gesto para ver las aplicaciones recientes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Muy bien!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Has completado el gesto para ver todas las aplicaciones"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animación del tutorial, haz clic para pausar y reanudar la reproducción."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 2c0c378e34ed..e3e72635ca5c 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Nupp Kuva ekraanisäästja"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliit, ühendus on saadaval"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliit-SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hädaabikõned või 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">"signaal puudub"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"üks pulk"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"kaks pulka"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"kolm pulka"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"neli pulka"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"tugev signaal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Tööprofiil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Kõik ei pruugi sellest rõõmu tunda"</string> <string name="tuner_warning" msgid="1861736288458481650">"Süsteemi kasutajaliidese tuuner pakub täiendavaid võimalusi Androidi kasutajaliidese muutmiseks ja kohandamiseks. Need katselised funktsioonid võivad muutuda, rikki minna või tulevastest versioonidest kaduda. Olge jätkamisel ettevaatlik."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Kogumi kohta tagasiside andmine"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lukustuskuva"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Märkme tegemine"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitegumtöö"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Jagatud ekraanikuva kasutamine, rakendus kuvatakse paremal"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Jagatud ekraanikuva kasutamine, rakendus kuvatakse vasakul"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Täisekraanile lülitamine"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Paremale või alumisele rakendusele lülitamine jagatud ekraani ajal"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vasakule või ülemisele rakendusele lülitamine jagatud ekraani ajal"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ekraanikuva jagamise ajal: ühe rakenduse asendamine teisega"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Toitemenüü"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lukustuskuva"</string> - <string name="finder_active" msgid="7907846989716941952">"Saate selle telefoni funktsiooniga Leia mu seade leida ka siis, kui see on välja lülitatud"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Väljalülitamine …"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vaadake hooldusjuhiseid"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Avakuvale"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Hiljutiste rakenduste vaatamine"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pühkige puuteplaadil kolme sõrmega vasakule või paremale"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Tubli töö!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Tegite tagasiliikumise liigutuse."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Avakuvale"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pühkige puuteplaadil kolme sõrmega üles"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Väga hea!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Tegite avakuvale minemise liigutuse"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Hiljutiste rakenduste vaatamine"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pühkige üles ja hoidke kolme sõrme puuteplaadil"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Väga hea!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Tegite hiljutiste rakenduste vaatamise liigutuse."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hästi tehtud!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Tegite kõigi rakenduste vaatamise liigutuse"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Õpetlik animatsioon, klõpsake esitamise peatamiseks ja jätkamiseks."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index cfd6c6a5e495..e284597d9f90 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Erakutsi pantaila-babeslearen botoia"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelitea, konexioa erabilgarri"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelite bidezko SOS komunikazioa"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Larrialdi-deiak edo SOS komunikazioa"</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">"ez dago seinalerik"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"barra bat"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"bi barra"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"hiru barra"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"lau barra"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"seinale osoa"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Laneko profila"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Dibertsioa batzuentzat, baina ez guztientzat"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sistemaren erabiltzaile-interfazearen konfiguratzaileak Android erabiltzaile-interfazea moldatzeko eta pertsonalizatzeko modu gehiago eskaintzen dizkizu. Baliteke eginbide esperimental horiek hurrengo kaleratzeetan aldatuta, etenda edo desagertuta egotea. Kontuz erabili."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Bidali sortari buruzko oharrak"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Blokeatu pantaila"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Egin ohar bat"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Zeregin bat baino gehiago aldi berean exekutatzea"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Erabili pantaila zatitua eta ezarri aplikazio hau eskuinean"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Erabili pantaila zatitua eta ezarri aplikazio hau ezkerrean"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Aldatu pantaila osora"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Aldatu eskuineko edo beheko aplikaziora pantaila zatitua erabiltzean"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Aldatu ezkerreko edo goiko aplikaziora pantaila zatitua erabiltzean"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Pantaila zatituan zaudela, ordeztu aplikazio bat beste batekin"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Itzaltzeko menua"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantaila blokeatua"</string> - <string name="finder_active" msgid="7907846989716941952">"Itzalita badago ere aurki dezakezu telefonoa Bilatu nire gailua erabilita"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Itzaltzen…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ikusi zaintzeko urratsak"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Joan orri nagusira"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ikusi azkenaldiko aplikazioak"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Eginda"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Ederki!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ikasi duzu atzera egiteko keinua."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Joan orri nagusira"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pasatu 3 hatz gora ukipen-panelean"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bikain!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ikasi duzu orri nagusira joateko keinua"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ikusi azkenaldiko aplikazioak"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bikain!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Osatu duzu azkenaldiko aplikazioak ikusteko keinua."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bikain!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Osatu duzu aplikazio guztiak ikusteko keinua"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorialeko animazioa. Sakatu pausatzeko eta erreproduzitzeari berrekiteko."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 163d84bd8239..0abbd26714ed 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"دکمه نمایش دادن محافظ صفحهنمایش"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ماهواره، اتصال دردسترس است"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"درخواست کمک ماهوارهای"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"تماس اضطراری یا درخواست کمک اضطراری"</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">"یک خط"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"دو خط"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"سه خط"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"چهار خط"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"سیگنال کامل"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"نمایه کاری"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"برای بعضی افراد سرگرمکننده است اما نه برای همه"</string> <string name="tuner_warning" msgid="1861736288458481650">"«تنظیمکننده واسط کاربری سیستم» روشهای بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار میدهد. ممکن است این ویژگیهای آزمایشی تغییر کنند، خراب شوند یا در نسخههای آینده جود نداشته باشند. با احتیاط ادامه دهید."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ارائه بازخورد دستهای"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"استفاده از صفحهٔ دونیمه با قرار گرفتن برنامه در سمت راست"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"استفاده از صفحهٔ دونیمه با قرار گرفتن برنامه در سمت چپ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"رفتن به حالت تمامصفحه"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"رفتن به برنامه سمت راست یا پایین درحین استفاده از صفحهٔ دونیمه"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"رفتن به برنامه سمت چپ یا بالا درحین استفاده از صفحهٔ دونیمه"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"درحین صفحهٔ دونیمه: برنامهای را با دیگری جابهجا میکند"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"منوی روشن/خاموش"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"صفحه قفل"</string> - <string name="finder_active" msgid="7907846989716941952">"حتی وقتی این تلفن خاموش است، میتوانید با «پیدا کردن دستگاهم» آن را مکانیابی کنید"</string> <string name="shutdown_progress" msgid="5464239146561542178">"درحال خاموش شدن…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"دیدن اقدامات محافظتی"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"رفتن به صفحه اصلی"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"مشاهده برنامههای اخیر"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تمام"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"با سه انگشت روی صفحه لمسی تند به چپ یا راست بکشید."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"چه خوب!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"اشاره برگشت را تکمیل کردید."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"رفتن به صفحه اصلی"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"با سه انگشت روی صفحه لمسی تند به بالا بکشید"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"عالی است!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"اشاره رفتن به صفحه اصلی را تکمیل کردید"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"مشاهده برنامههای اخیر"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"با سه انگشت روی صفحه لمسی تند به بالا بکشید و نگه دارید"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"عالی است!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره «مشاهده برنامههای اخیر» را تمام کردید"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"اشاره «مشاهده همه برنامهها» را تمام کردید"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 1caac76c623e..03d1441444be 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Näytä näytönsäästäjän painike"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliitti, yhteys saatavilla"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hätäpuhelut tai Satellite 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">"ei signaalia"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"yksi palkki"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"kaksi palkkia"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"kolme palkkia"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"neljä palkkia"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"vahva signaali"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Työprofiili"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Ei sovellu kaikkien käyttöön"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner antaa lisämahdollisuuksia Android-käyttöliittymän muokkaamiseen. Nämä kokeelliset ominaisuudet voivat muuttua, lakata toimimasta tai kadota milloin tahansa. Jatka omalla vastuullasi."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Anna palautetta paketista"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lukitse näyttö"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Tee muistiinpano"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitaskaus"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Käytä jaettua näyttöä niin, että sovellus on oikealla"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Käytä jaettua näyttöä niin, että sovellus on vasemmalla"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Koko näytölle siirtyminen"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Vaihda sovellukseen oikealla tai alapuolella jaetussa näytössä"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vaihda sovellukseen vasemmalla tai yläpuolella jaetussa näytössä"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Jaetun näytön aikana: korvaa sovellus toisella"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Virtavalikko"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lukitusnäyttö"</string> - <string name="finder_active" msgid="7907846989716941952">"Voit löytää tämän puhelimen Paikanna laite ‑sovelluksella, vaikka se olisi sammutettuna"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Sammutetaan…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Katso huoltovaiheet"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Siirry etusivulle"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Katso viimeisimmät sovellukset"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Hienoa!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Olet oppinut Takaisin-eleen."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Siirry etusivulle"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pyyhkäise ylös kolmella sormella kosketuslevyllä"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Hienoa!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Olet oppinut eleen, jolla pääset takaisin aloitusnäytölle"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Katso viimeisimmät sovellukset"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Hienoa!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Olet oppinut Katso viimeisimmät sovellukset ‑eleen."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hienoa!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Olet oppinut Näytä kaikki sovellukset ‑eleen."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Ohjeanimaatio, klikkaa keskeyttääksesi ja jatkaaksesi."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 6d56ac1abf26..f55fb0011423 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Afficher le bouton de l\'écran de veille"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite accessible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Appels d\'urgence ou 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">"aucun signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"une barre"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"deux barres"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"trois barres"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"quatre barres"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal excellent"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner vous propose de nouvelles manières d\'adapter et de personnaliser l\'interface utilisateur d\'Android. Ces fonctionnalités expérimentales peuvent être modifiées, cesser de fonctionner ou disparaître dans les versions futures. À utiliser avec prudence."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Fournir des commentaires groupés"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Verrouiller l\'écran"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Prendre une note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitâche"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utiliser l\'Écran divisé avec l\'appli à droite"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utiliser l\'Écran divisé avec l\'appli à gauche"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Passer au mode plein écran"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'Écran divisé"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'appli à gauche ou au-dessus avec l\'Écran divisé"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode d\'écran divisé : remplacer une appli par une autre"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu de l\'interrupteur"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string> - <string name="finder_active" msgid="7907846989716941952">"Vous pouvez localiser ce téléphone à l\'aide de Localiser mon appareil, même lorsqu\'il est éteint"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Arrêt en cours…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Retour à la page d\'accueil"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Balayez votre pavé tactile vers la gauche ou vers la droite avec trois doigts"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bien!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste de retour en arrière."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Retour à la page d\'accueil"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Balayez votre pavé tactile vers le haut avec trois doigts"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bon travail!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Vous avez appris le geste pour revenir à l\'écran d\'accueil"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Afficher les applis récentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Balayez votre pavé tactile vers le haut avec trois doigts, puis maintenez-les en place"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bon travail!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez effectué le geste pour afficher les applis récentes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Vous avez appris le geste pour afficher toutes les applis"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation du tutoriel; cliquer ici pour mettre en pause et reprendre la lecture."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index fd9854b7b235..138cfc92dbcd 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Afficher le bouton \"Économiseur d\'écran\""</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> @@ -643,7 +642,7 @@ <string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Vos applis personnelles sont connectées à Internet via <xliff:g id="VPN_APP">%1$s</xliff:g>. Votre fournisseur de VPN a accès à votre activité réseau (e-mails, données de navigation, etc.)."</string> <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string> <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Ouvrir les paramètres VPN"</string> - <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par tes parents. Ils peuvent voir et gérer certaines informations, telles que les applications que tu utilises, ta position et ton temps d\'utilisation de l\'appareil."</string> + <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par tes parents. Ils peuvent voir et gérer certaines informations, telles que les applications que tu utilises, ta position et ton temps devant l\'écran."</string> <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string> <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string> <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé, trop de tentatives d\'authentification"</string> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Appels d\'urgence ou 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">"aucun signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"faible"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"moyen"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"bon"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"très bon"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"excellent signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner vous propose de nouvelles manières d\'adapter et de personnaliser l\'interface utilisateur Android. Ces fonctionnalités expérimentales peuvent être modifiées, cesser de fonctionner ou disparaître dans les versions futures. À utiliser avec prudence."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Envoyer des commentaires groupés"</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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Verrouiller l\'écran"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Créer une note"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitâche"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Utiliser l\'écran partagé avec l\'appli sur la droite"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Utiliser l\'écran partagé avec l\'appli sur la gauche"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Passer en plein écran"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'appli à droite ou en dessous avec l\'écran partagé"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passez à l\'appli à gauche ou au-dessus avec l\'écran partagé"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En mode écran partagé : Remplacer une appli par une autre"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu Marche/Arrêt"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string> - <string name="finder_active" msgid="7907846989716941952">"Vous pouvez localiser ce téléphone avec Localiser mon appareil même lorsqu\'il est éteint"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Arrêt…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string> @@ -1424,7 +1425,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> - <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrée"</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> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accessibilité"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Retour à l\'accueil"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Balayez vers la gauche ou la droite avec trois doigts sur le pavé tactile"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bravo !"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Vous avez appris le geste pour revenir en arrière"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Retour à l\'accueil"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Balayez vers le haut avec trois doigts sur le pavé tactile"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bravo !"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Vous avez appris le geste pour revenir à l\'écran d\'accueil"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Afficher les applis récentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Avec trois doigts, balayez le pavé tactile vers le haut et maintenez la position"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bravo !"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez appris le geste pour afficher les applis récentes"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Vous avez appris le geste pour afficher toutes les applis"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation du tutoriel, cliquez pour mettre en pause et reprendre la lecture."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 96b858b62a7f..d04d04325ddf 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botón para mostrar o protector de pantalla"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión dispoñible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emerxencia ou 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">"non hai cobertura"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"unha barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dúas barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tres barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"catro barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinal completo"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de traballo"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversión só para algúns"</string> <string name="tuner_warning" msgid="1861736288458481650">"O configurador da IU do sistema ofréceche formas adicionais de modificar e personalizar a interface de usuario de Android. Estas funcións experimentais poden cambiar, interromperse ou desaparecer en futuras versións. Continúa con precaución."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar comentarios agrupados"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Crear nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefa"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar pantalla dividida coa aplicación na dereita"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar pantalla dividida coa aplicación na esquerda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Cambiar a pantalla completa"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar á aplicación da dereita ou de abaixo coa pantalla dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar á aplicación da esquerda ou de arriba coa pantalla dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"En modo de pantalla dividida: Substituír unha aplicación por outra"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de acendido"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string> - <string name="finder_active" msgid="7907846989716941952">"Podes atopar este teléfono (mesmo se está apagado) con Localizar o meu dispositivo"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Apagando…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantemento"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir ao inicio"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Consultar aplicacións recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Feito"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Pasa tres dedos cara á esquerda ou cara á dereita no panel táctil"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Excelente!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Completaches o titorial do xesto de retroceso."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir ao inicio"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Pasa tres dedos cara arriba no panel táctil"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ben feito!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Completaches o titorial do xesto para ir á pantalla de inicio"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Consultar aplicacións recentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Pasa tres dedos cara arriba e mantenos premidos no panel táctil"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Moi ben!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaches o titorial do xesto de consultar aplicacións recentes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben feito!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Completaches o titorial do xesto de ver todas as aplicacións"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animación do titorial, fai clic para poñelo en pausa ou retomar a reprodución."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index fb494c1dd7dd..327753dadbc1 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"સ્ક્રીનસેવર બટન બતાવો"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"સૅટલાઇટ, કનેક્શન ઉપલબ્ધ છે"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ઇમર્જન્સી સૅટલાઇટ સહાય"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ઇમર્જન્સી કૉલ અથવા 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">"એક બાર"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"બે બાર"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"ત્રણ બાર"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ચાર બાર"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"સિગ્નલ પૂર્ણ છે"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ઑફિસની પ્રોફાઇલ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"કેટલાક માટે મજા પરંતુ બધા માટે નહીં"</string> <string name="tuner_warning" msgid="1861736288458481650">"સિસ્ટમ UI ટ્યૂનર તમને Android વપરાશકર્તા ઇન્ટરફેસને ટ્વીક અને કસ્ટમાઇઝ કરવાની વધારાની રીતો આપે છે. ભાવિ રીલિઝેસમાં આ પ્રાયોગિક સુવિધાઓ બદલાઈ, ભંગ અથવા અદૃશ્ય થઈ શકે છે. સાવધાની સાથે આગળ વધો."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"બંડલ પ્રતિસાદ પ્રદાન કરો"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"હાલની ઍપને જમણી બાજુએ રાખીને વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"હાલની ઍપને ડાબી બાજુએ રાખીને વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"પૂર્ણ સ્ક્રીન પર સ્વિચ કરો"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે જમણી બાજુ કે નીચેની ઍપ પર સ્વિચ કરો"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે ડાબી બાજુની કે ઉપરની ઍપ પર સ્વિચ કરો"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"વિભાજિત સ્ક્રીન દરમિયાન: એક ઍપને બીજી ઍપમાં બદલો"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string> - <string name="finder_active" msgid="7907846989716941952">"આ ફોનનો પાવર બંધ હોય ત્યારે પણ Find My Device વડે તમે તેનું લોકેશન જાણી શકો છો"</string> <string name="shutdown_progress" msgid="5464239146561542178">"શટ ડાઉન કરી રહ્યાં છીએ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"સારસંભાળના પગલાં જુઓ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"હોમ પર જાઓ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"તાજેતરની ઍપ જુઓ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"થઈ ગયું"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"તમારા ટચપૅડ પર ત્રણ આંગળીનો ઉપયોગ કરીને ડાબે કે જમણે સ્વાઇપ કરો"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"સરસ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"હોમ પર જાઓ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"તમારા ટચપૅડ પર ત્રણ આંગળી વડે ઉપરની તરફ સ્વાઇપ કરો"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ખૂબ સરસ કામ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"તમે હોમ સ્ક્રીન પર જવાનો સંકેત પૂર્ણ કર્યો"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"તાજેતરની ઍપ જુઓ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"તમારા ટચપૅડ પર ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ખૂબ સરસ કામ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \'તાજેતરની ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"તમે \'બધી ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$dમાંથી %1$d લેવલ"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index c84a3eb936bb..1d3280c9193d 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -753,6 +753,20 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सैटलाइट कनेक्शन उपलब्ध है"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"सैटलाइट एसओएस"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"आपातकालीन कॉल या एसओएस"</string> + <!-- no translation found for accessibility_phone_string_format (7798841417881811812) --> + <skip /> + <!-- no translation found for accessibility_no_signal (7052827511409250167) --> + <skip /> + <!-- no translation found for accessibility_one_bar (5342012847647834506) --> + <skip /> + <!-- no translation found for accessibility_two_bars (122628483354508429) --> + <skip /> + <!-- no translation found for accessibility_three_bars (5143286602926069024) --> + <skip /> + <!-- no translation found for accessibility_four_bars (8838495563822541844) --> + <skip /> + <!-- no translation found for accessibility_signal_full (1519655809806462972) --> + <skip /> <string name="accessibility_managed_profile" msgid="4703836746209377356">"वर्क प्रोफ़ाइल"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"कुछ के लिए मज़ेदार लेकिन सबके लिए नहीं"</string> <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम यूज़र इंटरफ़ेस (यूआई) ट्यूनर, आपको Android यूज़र इंटरफ़ेस में सुधार लाने और उसे अपनी पसंद के हिसाब से बदलने के कुछ और तरीके देता है. प्रयोग के तौर पर इस्तेमाल हो रहीं ये सुविधाएं आगे चल कर रिलीज़ की जा सकती हैं, रोकी जा सकती हैं या दिखाई देना बंद हो सकती हैं. सावधानी से आगे बढ़ें."</string> @@ -786,7 +800,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"बंडल के बारे में सुझाव/राय दें या शिकायत करें"</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> @@ -872,12 +885,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"स्प्लिट स्क्रीन की सुविधा चालू करें और इस ऐप्लिकेशन को दाईं ओर दिखाएं"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"स्प्लिट स्क्रीन की सुविधा चालू करें और इस ऐप्लिकेशन को बाईं ओर दिखाएं"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"फ़ुल स्क्रीन पर स्विच करें"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन पर, दाईं ओर या नीचे के ऐप पर स्विच करने के लिए"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन पर, बाईं ओर या ऊपर के ऐप पर स्विच करने के लिए"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीन के दौरान: एक ऐप्लिकेशन को दूसरे ऐप्लिकेशन से बदलें"</string> @@ -979,7 +989,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेन्यू"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्क्रीन"</string> - <string name="finder_active" msgid="7907846989716941952">"Find My Device की मदद से, फ़ोन बंद होने पर भी इस फ़ोन की जगह की जानकारी का पता लगाया जा सकता है"</string> <string name="shutdown_progress" msgid="5464239146561542178">"बंद हो रहा है…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिवाइस के रखरखाव के तरीके देखें"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string> @@ -1466,22 +1475,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रीन पर जाएं"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"अपने टचपैड पर तीन उंगलियों से बाईं या दाईं ओर स्वाइप करें"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"बढ़िया!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, पिछली स्क्रीन पर वापस जाने का तरीका पता चल गया है."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"टचपैड का इस्तेमाल करके वापस जाने के लिए, तीन उंगलियों से बाईं या दाईं ओर स्वाइप करें"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होम स्क्रीन पर जाएं"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"बहुत बढ़िया!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"अब आपको हाथ के जेस्चर का इस्तेमाल करके होम स्क्रीन पर जाने का तरीका पता चल गया है"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"होम स्क्रीन पर जाने के लिए, अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें"</string> <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> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, सभी ऐप्लिकेशन देखने का तरीका पता चल गया है"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"सभी ऐप्लिकेशन देखने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं"</string> <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">"%2$d में से %1$d लेवल"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 6eabb6a2a9c9..6fc209fb8ad8 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS putem satelita"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Hitni pozivi ili 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">"nema signala"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dvije crtice"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tri crtice"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"četiri crtice"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"puni signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Poslovni profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zabava za neke, ali ne za sve"</string> <string name="tuner_warning" msgid="1861736288458481650">"Ugađanje korisničkog sučelja sustava pruža vam dodatne načine za prilagodbu korisničkog sučelja Androida. Te se eksperimentalne značajke mogu promijeniti, prekinuti ili nestati u budućim izdanjima. Nastavite uz oprez."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Pošaljite povratne informacije o paketu"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaključavanje zaslona"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Pisanje bilješke"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Obavljanje više zadataka"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Upotreba podijeljenog zaslona s aplikacijom s desne strane"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Upotreba podijeljenog zaslona s aplikacijom s lijeve strane"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Prebacivanje na cijeli zaslon"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prelazak na aplikaciju zdesna ili ispod uz podijeljeni zaslon"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prelazak na aplikaciju slijeva ili iznad uz podijeljeni zaslon"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijekom podijeljenog zaslona: zamijeni aplikaciju drugom"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Izbornik tipke za uključivanje/isključivanje"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani zaslon"</string> - <string name="finder_active" msgid="7907846989716941952">"Telefon možete pronaći pomoću usluge Pronađi moj uređaj čak i kada je isključen"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Isključivanje…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pročitajte upute za održavanje"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte što trebate učiniti"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Na početni zaslon"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Pregled nedavnih aplikacija"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Prijeđite ulijevo ili udesno trima prstima na dodirnoj podlozi"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Odlično!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Napravili ste pokret za povratak."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Na početnu stranicu"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Prijeđite prema gore trima prstima na dodirnoj podlozi"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Sjajno!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Napravili ste pokret za otvaranje početnog zaslona"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Pregled nedavnih aplikacija"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Prijeđite prema gore trima prstima na dodirnoj podlozi i zadržite pritisak"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Napravili ste pokret za prikaz nedavno korištenih aplikacija."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Napravili ste pokret za prikaz svih aplikacija"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacija u vodiču, kliknite za pauziranje i nastavak reprodukcije."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 2ee7b24fbe7f..669d59672c63 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Képernyőkímélő gomb megjelenítése"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Műhold, van rendelkezésre álló kapcsolat"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Műholdas SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Segélyhívás vagy 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">"nincs jel"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"egy sáv"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"két sáv"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"három sáv"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"négy sáv"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"teljes jelerősség"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Munkaprofil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Egyeseknek tetszik, másoknak nem"</string> <string name="tuner_warning" msgid="1861736288458481650">"A Kezelőfelület-hangoló az Android felhasználói felületének szerkesztéséhez és testreszabásához nyújt további megoldásokat. Ezek a kísérleti funkciók változhatnak vagy megsérülhetnek a későbbi kiadásokban, illetve eltűnhetnek azokból. Körültekintően járjon el."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Visszajelzés küldése a csomagról"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lezárási képernyő"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Jegyzetelés"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Osztott képernyő használata, az alkalmazás a jobb oldalon van"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Osztott képernyő használata, az alkalmazás a bal oldalon van"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Váltás teljes képernyőre"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Váltás a jobb oldalt, illetve lent lévő appra osztott képernyő esetén"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Váltás a bal oldalt, illetve fent lévő appra osztott képernyő esetén"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Osztott képernyőn: az egyik alkalmazás lecserélése egy másikra"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Bekapcsológombhoz tartozó menü"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lezárási képernyő"</string> - <string name="finder_active" msgid="7907846989716941952">"A Készülékkereső segítségével akár a kikapcsolt telefon helyét is meghatározhatja."</string> <string name="shutdown_progress" msgid="5464239146561542178">"Leállítás…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Olvassa el a kímélő használat lépéseit"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ugrás a főoldalra"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Legutóbbi alkalmazások megtekintése"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kész"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Csúsztassa gyorsan három ujját balra vagy jobbra az érintőpadon."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Remek!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Teljesítette a visszalépési kézmozdulatot."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ugrás a főoldalra"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Csúsztasson gyorsan felfelé három ujjával az érintőpadon."</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Kiváló!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Teljesítette a kezdőképernyőre lépés kézmozdulatát."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Legutóbbi alkalmazások megtekintése"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Csúsztasson gyorsan felfelé három ujjal az érintőpadon, és tartsa rajta lenyomva az ujjait."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kiváló!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Teljesítette a legutóbbi alkalmazások megtekintésének kézmozdulatát."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Teljesítette az összes alkalmazás megtekintésének kézmozdulatát."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Útmutató animáció. Kattintson a szüneteltetéshez és a lejátszás folytatásához."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index d43beb8b6407..095c2adf1a8b 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"«Ցույց տալ էկրանապահը» կոճակ"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Հասանելի է արբանյակային կապ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Շտապ կանչեր կամ 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">"մեկ գիծ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"երկու գիծ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"երեք գիծ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"չորս գիծ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ազդանշանը ուժեղ է"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Աշխատանքային պրոֆիլ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Զվարճանք մեկ՝ որոշակի մարդու համար"</string> <string name="tuner_warning" msgid="1861736288458481650">"Համակարգի ՕՄ-ի կարգավորիչը հնարավորություն է տալիս հարմարեցնել Android-ի օգտատիրոջ միջերեսը: Այս փորձնական գործառույթները կարող են հետագա թողարկումների մեջ փոփոխվել, խափանվել կամ ընդհանրապես չհայտնվել: Եթե շարունակում եք, զգուշացեք:"</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Հավաքածուի մասին կարծիք հայտնել"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Տրոհել էկրանը և տեղավորել այս հավելվածը աջ կողմում"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Տրոհել էկրանը և տեղավորել այս հավելվածը ձախ կողմում"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Անցնել լիաէկրան ռեժիմի"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Անցեք աջ կողմի կամ ներքևի հավելվածին տրոհված էկրանի միջոցով"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Անցեք աջ կողմի կամ վերևի հավելվածին տրոհված էկրանի միջոցով"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Տրոհված էկրանի ռեժիմում մեկ հավելվածը փոխարինել մյուսով"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Սնուցման կոճակի ընտրացանկ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string> - <string name="finder_active" msgid="7907846989716941952">"«Գտնել իմ սարքը» ծառայության օգնությամբ դուք կարող եք տեղորոշել այս հեռախոսը, նույնիսկ եթե այն անջատված է"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Անջատվում է…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ինչպես անցնել հիմնական էկրան"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Դիտել վերջին հավելվածները"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Պատրաստ է"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Հետ գնալ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Հպահարթակի վրա երեք մատով սահեցրեք ձախ կամ աջ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Գերազանց է"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Դուք սովորեցիք հետ գնալու ժեստը։"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Անցում հիմնական էկրան"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Հպահարթակի վրա երեք մատով սահեցրեք վերև"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Կեցցե՛ք"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Դիտել վերջին հավելվածները"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Երեք մատով սահեցրեք վերև և սեղմած պահեք հպահարթակին"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Կեցցե՛ք"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Դուք կատարեցիք վերջին օգտագործված հավելվածների դիտման ժեստը։"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Դուք սովորեցիք բոլոր հավելվածները դիտելու ժեստը"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 095b35bca77a..b5b588891eee 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Tampilkan tombol screensaver"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, koneksi tersedia"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Panggilan darurat atau 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">"tidak ada sinyal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"satu batang"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dua batang"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tiga batang"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"empat batang"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinyal penuh"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Tidak semua orang menganggapnya baik"</string> <string name="tuner_warning" msgid="1861736288458481650">"Penyetel Antarmuka Pengguna Sistem memberikan cara tambahan untuk mengubah dan menyesuaikan antarmuka pengguna Android. Fitur eksperimental ini dapat berubah, rusak, atau menghilang dalam rilis di masa mendatang. Lanjutkan dengan hati-hati."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Berikan Masukan Gabungan"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci layar"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Buat catatan"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gunakan layar terpisah dengan aplikasi di sebelah kanan"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gunakan layar terpisah dengan aplikasi di sebelah kiri"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Beralih ke layar penuh"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Beralih ke aplikasi di bagian kanan atau bawah saat menggunakan layar terpisah"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Beralih ke aplikasi di bagian kiri atau atas saat menggunakan layar terpisah"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Dalam layar terpisah: ganti salah satu aplikasi dengan yang lain"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu daya"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Layar kunci"</string> - <string name="finder_active" msgid="7907846989716941952">"Anda dapat menemukan lokasi ponsel ini dengan Temukan Perangkat Saya meskipun ponsel dimatikan"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Sedang mematikan…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah-langkah perawatan"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Buka layar utama"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat aplikasi terbaru"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Geser ke kiri atau kanan menggunakan tiga jari di touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Sip!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah menyelesaikan gestur untuk kembali."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Buka layar utama"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Geser ke atas dengan tiga jari di touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Anda telah menyelesaikan gestur buka layar utama"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat aplikasi terbaru"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Geser ke atas dan tahan menggunakan tiga jari di touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bagus!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Oke!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah menyelesaikan gestur untuk melihat semua aplikasi"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animasi tutorial, klik untuk menjeda dan melanjutkan pemutaran."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 8a885f0efb77..a1ad51e84082 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Gervihnöttur, tenging tiltæk"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Gervihnattar-SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Neyðarsímtöl eða 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">"ekkert samband"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"eitt strik"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"tvö strik"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"þrjú strik"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"fjögur strik"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"fullt samband"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Vinnusnið"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Þetta er ekki allra"</string> <string name="tuner_warning" msgid="1861736288458481650">"Fínstillingar kerfisviðmóts gera þér kleift að fínstilla og sérsníða notendaviðmót Android. Þessir tilraunaeiginleikar geta breyst, bilað eða horfið í síðari útgáfum. Gakktu því hægt um gleðinnar dyr."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Senda inn ábendingu um pakka"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lásskjár"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Skrifa glósu"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Fjölvinnsla"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Notaðu skjáskiptingu fyrir forritið til hægri"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Notaðu skjáskiptingu fyrir forritið til vinstri"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Skipta yfir í allan skjáinn"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skiptu í forrit til hægri eða fyrir neðan þegar skjáskipting er notuð"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skiptu í forrit til vinstri eða fyrir ofan þegar skjáskipting er notuð"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Í skjáskiptingu: Skipta forriti út fyrir annað forrit"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aflrofavalmynd"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lásskjár"</string> - <string name="finder_active" msgid="7907846989716941952">"Þú getur fundið þennan síma með „Finna tækið mitt“, jafnvel þótt slökkt sé á honum"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Slekkur…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sjá varúðarskref"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Fara á heimaskjá"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Sjá nýleg forrit"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Lokið"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Strjúktu til hægri eða vinstri á snertifletinum með þremur fingrum"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Flott!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Þú laukst við að kynna þér bendinguna „til baka“."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Heim"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Strjúktu upp á snertifletinum með þremur fingrum"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Vel gert!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Þú framkvæmdir bendinguna „Fara á heimaskjá“"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Sjá nýleg forrit"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Vel gert!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Þú framkvæmdir bendinguna til að sjá nýleg forrit."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vel gert!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Þú framkvæmdir bendinguna „Sjá öll forrit“"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Leiðsagnarhreyfimynd, smelltu til að gera hlé og halda áfram að spila."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 790a80dbc543..03a6f54e9e61 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -704,7 +704,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Audio spaziale"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Off"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fisso"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Rilev. movim. testa"</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Tracciamento testa"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tocca per cambiare la modalità della suoneria"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modalità suoneria"</string> <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, tocca per cambiare la modalità della suoneria"</string> @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitare, connessione disponibile"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satellitare"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chiamate di emergenza o 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">"nessun segnale"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"due barre"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tre barre"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"quattro barre"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"massimo segnale"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profilo di lavoro"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Il divertimento riservato a pochi eletti"</string> <string name="tuner_warning" msgid="1861736288458481650">"L\'Ottimizzatore UI di sistema mette a disposizione altri metodi per modificare e personalizzare l\'interfaccia utente di Android. Queste funzioni sperimentali potrebbero cambiare, interrompersi o scomparire nelle versioni successive. Procedi con cautela."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Fornisci feedback sul bundle"</string> <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> @@ -976,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu del tasto di accensione"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Schermata di blocco"</string> - <string name="finder_active" msgid="7907846989716941952">"Puoi trovare questo smartphone tramite Trova il mio dispositivo anche quando è spento"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Arresto in corso…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Leggi le misure da adottare"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string> @@ -1463,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Vai alla schermata Home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Visualizza app recenti"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fine"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Scorri verso sinistra o destra con tre dita sul touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bene!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Hai completato il gesto Indietro."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Vai alla schermata Home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Scorri in alto con tre dita sul touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Ottimo lavoro!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Hai completato il gesto Vai alla schermata Home"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Visualizza app recenti"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Scorri verso l\'alto e tieni premuto con tre dita sul touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben fatto!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Hai completato il gesto Visualizza tutte le app."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animazione del tutorial: fai clic per mettere in pausa e riprendere la riproduzione."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 99939a86bc39..1d74a496aba2 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"לחצן להצגת שומר המסך"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"לוויין, יש חיבור זמין"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"תקשורת לוויינית למצב חירום"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"שיחות חירום או 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">"פס אחד"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"שני פסים"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"שלושה פסים"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ארבעה פסים"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"קליטה מלאה"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string> <string name="tuner_warning" msgid="1861736288458481650">"התכונה System UI Tuner מספקת לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, לא לעבוד כראוי או להיעלם בגרסאות עתידיות. יש להמשיך בזהירות."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"שליחת משוב על החבילה"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"שימוש במסך מפוצל כשהאפליקציה בצד ימין"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"שימוש במסך מפוצל כשהאפליקציה בצד שמאל"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"למסך מלא"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"מעבר לאפליקציה משמאל או למטה בזמן שימוש במסך מפוצל"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"מעבר לאפליקציה מימין או למעלה בזמן שימוש במסך מפוצל"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"כשהמסך מפוצל: החלפה בין אפליקציה אחת לאחרת"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"תפריט הפעלה"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"מסך נעילה"</string> - <string name="finder_active" msgid="7907846989716941952">"אפשר לאתר את הטלפון הזה עם שירות \'איפה המכשיר שלי\' גם כשהוא כבוי"</string> <string name="shutdown_progress" msgid="5464239146561542178">"בתהליך כיבוי…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"לצפייה בשלבי הטיפול"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"חזרה לדף הבית"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"מחליקים שמאלה או ימינה עם שלוש אצבעות על לוח המגע"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"איזה יופי!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"סיימת לתרגל את התנועה \'הקודם\'."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"מעבר למסך הבית"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"מחליקים כלפי מעלה עם שלוש אצבעות על לוח המגע"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"מעולה!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"סיימת לתרגל את תנועת החזרה למסך הבית"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"הצגת האפליקציות האחרונות"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"מחליקים למעלה עם שלוש אצבעות על לוח המגע ומשאירים אותן במגע עם הלוח"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"מעולה!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"סיימת לתרגל את התנועה להצגת האפליקציות האחרונות."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"סיימת לתרגל את התנועה להצגת כל האפליקציות"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 5fd029b25e5c..da74e231ef03 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"緊急通報または 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> + <string name="accessibility_two_bars" msgid="122628483354508429">"レベル 2"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"レベル 3"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"レベル 4"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"電波フル"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"仕事用プロファイル"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"一部の方のみお楽しみいただける限定公開ツール"</string> <string name="tuner_warning" msgid="1861736288458481650">"システムUI調整ツールでは、Androidユーザーインターフェースの調整やカスタマイズを行えます。これらの試験運用機能は今後のリリースで変更となったり、中止となったり、削除されたりする可能性がありますのでご注意ください。"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"バンドルに関するフィードバックを送信"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"分割画面の使用(アプリを右側に表示)"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"分割画面の使用(アプリを左側に表示)"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"全画面表示に切り替える"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"分割画面の使用時に右側または下部のアプリに切り替える"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"分割画面の使用時に左側または上部のアプリに切り替える"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"分割画面中: アプリを順に置換する"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源ボタン メニュー"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ロック画面"</string> - <string name="finder_active" msgid="7907846989716941952">"「デバイスを探す」を使うと、電源が OFF の状態でもこのスマートフォンの現在地を確認できます"</string> <string name="shutdown_progress" msgid="5464239146561542178">"シャットダウン中…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"取り扱いに関する手順をご覧ください"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string> @@ -1275,7 +1277,7 @@ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string> <string name="accessibility_bouncer" msgid="5896923685673320070">"画面ロックを設定"</string> - <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"指紋認証センサーに触れてください。スマートフォンの側面にある高さが低い方のボタンです。"</string> + <string name="accessibility_side_fingerprint_indicator_label" msgid="1673807833352363712">"指紋認証センサーに触れてください。スマートフォンの側面にあるボタンのうち、上側の短いボタンです。"</string> <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋認証センサー"</string> <string name="accessibility_authenticate_hint" msgid="798914151813205721">"認証"</string> <string name="accessibility_enter_hint" msgid="2617864063504824834">"デバイスを入力"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ホームに移動"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"最近使ったアプリを表示する"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"タッチパッドを 3 本の指で左または右にスワイプします"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"その調子です!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"「戻る」ジェスチャーを学習しました。"</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"タッチパッドを使用して戻るには、3 本の指で左または右にスワイプします"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ホームに移動"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"タッチパッドを 3 本の指で上にスワイプします"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"よくできました!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"「ホームに移動」ジェスチャーを学習しました"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"ホーム画面に移動するには、タッチパッドを 3 本の指で上にスワイプします"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"最近使ったアプリを表示する"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"タッチパッドを 3 本の指で上にスワイプして長押しします"</string> <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">"最近使ったアプリを表示するには、3 本の指でタッチパッドを上にスワイプして長押しします"</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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"「すべてのアプリを表示する」ジェスチャーを学習しました"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"すべてのアプリを表示するには、キーボードのアクションキーを押します"</string> <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> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 55d38c9ead8e..5a2015821fd0 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"გადაუდებელი ზარი ან 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">"ერთი ხაზი"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ორი ხაზი"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"სამი ხაზი"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ოთხი ხაზი"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"სრული სიგნალი"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"სამსახურის პროფილი"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ზოგისთვის გასართობია, მაგრამ არა ყველასთვის"</string> <string name="tuner_warning" msgid="1861736288458481650">"სისტემის UI ტუნერი გაძლევთ დამატებით გზებს Android-ის სამომხმარებლო ინტერფეისის პარამეტრების დაყენებისთვის. ეს ექსპერიმენტული მახასიათებლები შეიძლება შეიცვალოს, შეწყდეს ან გაქრეს მომავალ ვერსიებში. სიფრთხილით გააგრძელეთ."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ნაკრებზე გამოხმაურების წარმოდგენა"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ეკრანის გაყოფის გამოყენება აპზე მარჯვნივ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ეკრანის გაყოფის გამოყენება აპზე მარცხნივ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"სრულ ეკრანზე გადართვა"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ეკრანის გაყოფის გამოყენებისას აპზე მარჯვნივ ან ქვემოთ გადართვა"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ეკრანის გაყოფის გამოყენებისას აპზე მარცხნივ ან ზემოთ გადართვა"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ეკრანის გაყოფის დროს: ერთი აპის მეორით ჩანაცვლება"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ჩართვის მენიუ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ჩაკეტილი ეკრანი"</string> - <string name="finder_active" msgid="7907846989716941952">"შეგიძლიათ დაადგინოთ ამ ტელეფონის მდებარეობა ფუნქციით „ჩემი მოწყობილობის პოვნა“, მაშინაც კი, როდესაც ის გამორთულია"</string> <string name="shutdown_progress" msgid="5464239146561542178">"მიმდინარეობს გამორთვა…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"მისაღები ზომების გაცნობა"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"მთავარ ეკრანზე გადასვლა"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ბოლო აპების ნახვა"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ მარცხნივ ან მარჯვნივ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"მშვენიერია!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"თქვენი სენსორული პანელის კვლავ გამოსაყენებლად გადაფურცლეთ მარცხნივ ან მარჯვნივ სამი თითით"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"მთავარზე გადასვლა"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"შესანიშნავია!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"თქვენ შეასრულეთ მთავარ ეკრანზე გადასვლის ჟესტი"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით მთავარ ეკრანზე გადასავლელად"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ბოლო აპების ნახვა"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით და ხანგრძლივად დააჭირეთ"</string> <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> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"თქვენ დაასრულეთ ყველა აპის ნახვის ჟესტი"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე ყველა თქვენი აპის სანახავად"</string> <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> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 9b6dc953de12..5bd63b1b4d04 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Скринсейвер түймесін көрсету"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Жерсерік, байланыс бар."</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Құтқару қызметіне қоңырау шалу немесе 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">"бір жолақ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"екі жолақ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"үш жолақ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"төрт жолақ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"толық сигнал"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Жұмыс профилі"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Кейбіреулерге қызық, бірақ барлығына емес"</string> <string name="tuner_warning" msgid="1861736288458481650">"Жүйелік пайдаланушылық интерфейс тюнері Android пайдаланушылық интерфейсін реттеудің қосымша жолдарын береді. Бұл эксперименттік мүмкіндіктер болашақ шығарылымдарда өзгеруі, бұзылуы немесе жоғалуы мүмкін. Сақтықпен жалғастырыңыз."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Пакет туралы пікір жіберу"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Қолданбаны бөлінген экранның оң жағынан пайдалану"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Қолданбаны бөлінген экранның сол жағынан пайдалану"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Толық экранға ауысу"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлінген экранда оң не төмен жақтағы қолданбаға ауысу"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлінген экранда сол не жоғары жақтағы қолданбаға ауысу"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлу кезінде: бір қолданбаны басқасымен алмастыру"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Қуат мәзірі"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Құлыптаулы экран"</string> - <string name="finder_active" msgid="7907846989716941952">"Сіз бұл телефонды, ол тіпті өшірулі тұрса да Find My Device арқылы таба аласыз."</string> <string name="shutdown_progress" msgid="5464239146561542178">"Өшіріліп жатыр…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Пайдалану нұсқаулығын қараңыз"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Негізгі бетке өту"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Соңғы қолданбаларды көру"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Дайын"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артқа"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Сенсорлық тақтада үш саусақпен оңға немесе солға сырғытыңыз."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Керемет!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Артқа қайту қимылын аяқтадыңыз."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Негізгі экранға өту"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Сенсорлық тақтада үш саусақпен жоғары сырғытыңыз."</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Жарайсыз!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Негізгі экранға қайту қимылын орындадыңыз."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Соңғы қолданбаларды көру"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Сенсорлық тақтада үш саусақпен жоғары сырғытып, басып тұрыңыз."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Жарайсыз!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Соңғы қолданбаларды көру қимылын орындадыңыз."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Барлық қолданбаны көру қимылын орындадыңыз."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 50f5fa05aff5..fa3fc664c0f8 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ផ្កាយរណប អាចតភ្ជាប់បាន"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ការប្រកាសអាសន្នតាមផ្កាយរណប"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់ ឬ 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">"មួយកាំ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ពីរកាំ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"បីកាំ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"បួនកាំ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"សញ្ញាពេញ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"កម្រងព័ត៌មានការងារ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ល្អសម្រាប់អ្នកប្រើមួយចំនួន តែមិនសម្រាប់គ្រប់គ្នាទេ"</string> <string name="tuner_warning" msgid="1861736288458481650">"កម្មវិធីសម្រួល UI ប្រព័ន្ធផ្តល់ជូនអ្នកនូវមធ្យោបាយបន្ថែមទៀតដើម្បីកែសម្រួល និងប្តូរចំណុចប្រទាក់អ្នកប្រើ Android តាមបំណង។ លក្ខណៈពិសេសសាកល្បងនេះអាចនឹងផ្លាស់ប្តូរ បំបែក ឬបាត់បង់បន្ទាប់ពីការចេញផ្សាយនាពេលអនាគត។ សូមបន្តដោយប្រុងប្រយ័ត្ន។"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ផ្ដល់មតិកែលម្អជាកញ្ចប់"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីនៅខាងស្ដាំ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីនៅខាងឆ្វេង"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ប្ដូរទៅអេក្រង់ពេញ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ប្ដូរទៅកម្មវិធីនៅខាងស្ដាំ ឬខាងក្រោម ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ប្ដូរទៅកម្មវិធីនៅខាងឆ្វេង ឬខាងលើ ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ក្នុងអំឡុងពេលប្រើមុខងារបំបែកអេក្រង់៖ ជំនួសកម្មវិធីពីមួយទៅមួយទៀត"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ម៉ឺនុយថាមពល"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"អេក្រង់ចាក់សោ"</string> - <string name="finder_active" msgid="7907846989716941952">"អ្នកអាចកំណត់ទីតាំងទូរសព្ទនេះដោយប្រើ \"រកឧបករណ៍របស់ខ្ញុំ\" សូម្បីនៅពេលបិទថាមពល"</string> <string name="shutdown_progress" msgid="5464239146561542178">"កំពុងបិទ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"មើលជំហានថែទាំ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"មើលជំហានថែទាំ"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ទៅទំព័រដើម"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"មើលកម្មវិធីថ្មីៗ"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"អូសទៅឆ្វេង ឬស្ដាំដោយប្រើម្រាមដៃបីនៅលើផ្ទាំងប៉ះរបស់អ្នក"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ល្អ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"អ្នកបានបញ្ចប់ចលនាថយក្រោយហើយ។"</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"ដើម្បីត្រឡប់ក្រោយដោយប្រើផ្ទាំងប៉ះរបស់អ្នក សូមអូសទៅឆ្វេង ឬស្ដាំដោយប្រើម្រាមដៃបី"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ទៅទំព័រដើម"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"អូសឡើងលើដោយប្រើម្រាមដៃបីនៅលើផ្ទាំងប៉ះរបស់អ្នក"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ធ្វើបានល្អ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់ទំព័រដើមហើយ"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"អូសឡើងលើដោយប្រើម្រាមដៃបីលើផ្ទាំងប៉ះរបស់អ្នក ដើម្បីទៅកាន់អេក្រង់ដើមរបស់អ្នក"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"មើលកម្មវិធីថ្មីៗ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបីលើផ្ទាំងប៉ះរបស់អ្នក"</string> <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> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"អ្នកបានបញ្ចប់ចលនាមើលកម្មវិធីទាំងអស់ហើយ"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"ចុចគ្រាប់ចុចសកម្មភាពលើក្ដារចុចរបស់អ្នក ដើម្បីមើលកម្មវិធីទាំងអស់របស់អ្នក"</string> <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> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index a3718d3ffa96..e53988c8c648 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"ತುರ್ತು ಕರೆಗಳು ಅಥವಾ 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">"ಒಂದು ಬಾರ್"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ಎರಡು ಬಾರ್ಗಳು"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"ಮೂರು ಬಾರ್ಗಳು"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ನಾಲ್ಕು ಬಾರ್ಗಳು"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ಸಿಗ್ನಲ್ ಪೂರ್ತಿ ಇದೆ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ಕೆಲವರಿಗೆ ಮೋಜು ಆಗಿದೆ ಎಲ್ಲರಿಗೆ ಇಲ್ಲ"</string> <string name="tuner_warning" msgid="1861736288458481650">"ಸಿಸ್ಟಂ UI ಟ್ಯೂನರ್ ನಿಮಗೆ Android ಬಳಕೆದಾರ ಅಂತರಸಂಪರ್ಕವನ್ನು ಸರಿಪಡಿಸಲು ಮತ್ತು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಹೆಚ್ಚುವರಿ ಮಾರ್ಗಗಳನ್ನು ನೀಡುತ್ತದೆ. ಈ ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯಗಳು ಭವಿಷ್ಯದ ಬಿಡುಗಡೆಗಳಲ್ಲಿ ಬದಲಾಗಬಹುದು, ವಿರಾಮವಾಗಬಹುದು ಅಥವಾ ಕಾಣಿಸಿಕೊಳ್ಳದಿರಬಹುದು. ಎಚ್ಚರಿಕೆಯಿಂದ ಮುಂದುವರಿಯಿರಿ."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ಬಂಡಲ್ ಫೀಡ್ಬ್ಯಾಕ್ ಅನ್ನು ಒದಗಿಸಿ"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ಬಲಭಾಗದಲ್ಲಿ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ಎಡಭಾಗದಲ್ಲಿ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ಫುಲ್ಸ್ಕ್ರೀನ್ ಮೋಡ್ಗೆ ಬದಲಿಸಿ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಬಲಭಾಗ ಅಥವಾ ಕೆಳಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಎಡಭಾಗ ಅಥವಾ ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸುವ ಸಮಯದಲ್ಲಿ: ಒಂದು ಆ್ಯಪ್ನಿಂದ ಮತ್ತೊಂದು ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ಪವರ್ ಮೆನು"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string> - <string name="finder_active" msgid="7907846989716941952">"ಪವರ್ ಆಫ್ ಆಗಿರುವಾಗಲೂ ನೀವು Find My Device ಮೂಲಕ ಈ ಫೋನ್ ಅನ್ನು ಪತ್ತೆ ಮಾಡಬಹುದು"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ಶಟ್ ಡೌನ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> @@ -1466,23 +1468,33 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ಮುಗಿದಿದೆ"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ಚೆನ್ನಾಗಿದೆ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ಭೇಷ್!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ನೀವು ಗೋ ಹೋಮ್ ಜೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ಭೇಷ್!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳ ಜೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ನೀವು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳ ಜೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string> - <string name="tutorial_animation_content_description" msgid="2698816574982370184">"ಟ್ಯುಟೋರಿಯಲ್ ಅನಿಮೇಷನ್, ವಿರಾಮಗೊಳಿಸಲು ಮತ್ತು ಪ್ಲೇ ಪುನರಾರಂಭಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> + <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">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index ee19ad2c5af2..dc6fcda09d8f 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"화면 보호기 버튼 표시"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"긴급 전화 또는 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> + <string name="accessibility_two_bars" msgid="122628483354508429">"신호 막대가 2개입니다"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"신호 막대가 3개입니다"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"신호 막대가 4개입니다"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"신호가 강합니다"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"직장 프로필"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"마음에 들지 않을 수도 있음"</string> <string name="tuner_warning" msgid="1861736288458481650">"시스템 UI 튜너를 사용하면 Android 사용자 인터페이스를 변경 및 맞춤설정할 수 있습니다. 이러한 실험실 기능은 향후 출시 버전에서는 변경되거나 다운되거나 사라질 수 있습니다. 신중하게 진행하시기 바랍니다."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"번들 관련 의견 보내기"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"앱이 오른쪽에 오도록 화면 분할 사용"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"앱이 왼쪽에 오도록 화면 분할 사용"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"전체 화면으로 전환"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"화면 분할을 사용하는 중에 오른쪽 또는 아래쪽에 있는 앱으로 전환"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"화면 분할을 사용하는 중에 왼쪽 또는 위쪽에 있는 앱으로 전환하기"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"화면 분할 중: 다른 앱으로 바꾸기"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"전원 메뉴"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"잠금 화면"</string> - <string name="finder_active" msgid="7907846989716941952">"전원이 꺼져 있을 때도 내 기기 찾기로 이 휴대전화를 찾을 수 있습니다."</string> <string name="shutdown_progress" msgid="5464239146561542178">"종료 중…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"해결 방법 확인하기"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"홈으로 이동"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"최근 앱 보기"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"완료"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"뒤로"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"세 손가락을 사용해 터치패드에서 왼쪽 또는 오른쪽으로 스와이프하세요."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"훌륭합니다"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"돌아가기 동작을 완료했습니다."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"홈으로 이동"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"세 손가락을 사용해 터치패드에서 위로 스와이프하세요."</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"잘하셨습니다"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"홈으로 이동 동작을 완료했습니다."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"최근 앱 보기"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"세 손가락을 사용해 터치패드에서 위로 스와이프한 후 잠시 기다리세요."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"아주 좋습니다"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"최근 앱 보기 동작을 완료했습니다."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"모든 앱 보기 동작을 완료했습니다."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d단계 중 %1$d단계"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 7ebfdec49c30..83ec250da016 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Көшөгө баскычын көрсөтүү"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"Шашылыш чалуулар же 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">"бир мамыча"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"эки мамыча"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"үч мамыча"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"төрт мамыча"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"толук сигнал"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Жумуш профили"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Баарына эле жага бербейт"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner Android колдонуучу интерфейсин жөнгө салып жана ыңгайлаштыруунун кошумча ыкмаларын сунуштайт. Бул сынамык функциялар кийинки чыгарылыштарда өзгөрүлүп, бузулуп же жоголуп кетиши мүмкүн. Абайлап колдонуңуз."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Топтом тууралуу пикир билдирүү"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Колдонмону оңго жылдырып, экранды бөлүү"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Колдонмону солго жылдырып, экранды бөлүү"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Толук экранга которулуу"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлүнгөн экранда сол же төмөн жактагы колдонмого которулуу"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлүнгөн экранды колдонуп жатканда сол же жогору жактагы колдонмого которулуңуз"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлүү режиминде бир колдонмону экинчисине алмаштыруу"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Кубат баскычынын менюсу"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Кулпуланган экран"</string> - <string name="finder_active" msgid="7907846989716941952">"Бул телефон өчүк болсо да, аны \"Түзмөгүм кайда?\" кызматы аркылуу таба аласыз"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Өчүрүлүүдө…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Тейлөө кадамдарын көрүңүз"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Башкы бетке өтүү"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Акыркы колдонмолорду көрүү"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Бүттү"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Сенсордук тактаны үч манжаңыз менен солго же оңго сүрүңүз"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Сонун!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"\"Артка\" жаңсоосун үйрөндүңүз."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Башкы бетке өтүү"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Сенсордук тактаны үч манжаңыз менен жогору сүрүңүз"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Азаматсыз!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Акыркы колдонмолорду көрүү"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Сенсордук тактаны үч манжаңыз менен өйдө сүрүп, кармап туруңуз"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Азаматсыз!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Акыркы колдонмолорду көрүү жаңсоосун аткардыңыз."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Бардык колдонмолорду көрүү жаңсоосун аткардыңыз"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d ичинен %1$d-деңгээл"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 151687fd4050..53d3bca20fa5 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"ໂທສຸກເສີນ ຫຼື 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> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 ຂີດ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 ຂີດ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 ຂີດ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ສັນຍານເຕັມ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ມ່ວນຊື່ນສຳລັບບາງຄົນ ແຕ່ບໍ່ແມ່ນສຳລັບທຸກຄົນ"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner ໃຫ້ທ່ານມີວິທີພິເສດຕື່ມອີກໃນການປັບປ່ຽນ ແລະຕົບແຕ່ງສ່ວນຕໍ່ປະສານຜູ້ໃຊ້ຂອງ Android. ຄຸນສົມບັດທົດລອງໃຊ້ເຫຼົ່ານີ້ອາດຈະປ່ຽນແປງ, ຢຸດເຊົາ ຫຼືຫາຍໄປໃນການວາງຈຳໜ່າຍໃນອະນາຄົດ. ຈົ່ງດຳເນີນຕໍ່ດ້ວຍຄວາມລະມັດລະວັງ."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ໃຫ້ຄຳຕິຊົມເປັນຊຸດ"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ໃຊ້ໂໝດແບ່ງໜ້າຈໍໂດຍໃຫ້ແອັບຢູ່ເບື້ອງຂວາ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ໃຊ້ໂໝດແບ່ງໜ້າຈໍໂດຍໃຫ້ແອັບຢູ່ເບື້ອງຊ້າຍ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ສະຫຼັບໄປໃຊ້ໂໝດເຕັມຈໍ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຂວາ ຫຼື ທາງລຸ່ມໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຊ້າຍ ຫຼື ທາງເທິງໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ໃນລະຫວ່າງແບ່ງໜ້າຈໍ: ໃຫ້ປ່ຽນຈາກແອັບໜຶ່ງເປັນອີກແອັບໜຶ່ງ"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ເມນູເປີດປິດ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ໜ້າຈໍລັອກ"</string> - <string name="finder_active" msgid="7907846989716941952">"ທ່ານສາມາດຊອກຫາສະຖານທີ່ຂອງໂທລະສັບເຄື່ອງນີ້ໄດ້ດ້ວຍແອັບຊອກຫາອຸປະກອນຂອງຂ້ອຍເຖິງແມ່ນວ່າຈະປິດເຄື່ອງຢູ່ກໍຕາມ"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ກຳລັງປິດເຄື່ອງ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ໄປຫາໜ້າຫຼັກ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ເບິ່ງແອັບຫຼ້າສຸດ"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ປັດຊ້າຍ ຫຼື ຂວາໂດຍໃຊ້ມືສາມນິ້ວຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ດີ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"ເພື່ອກັບຄືນໂດຍໃຊ້ແຜ່ນສໍາຜັດຂອງທ່ານ, ໃຫ້ປັດຊ້າຍ ຫຼື ຂວາໂດຍໃຊ້ສາມນິ້ວ"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ໄປຫາໜ້າຫຼັກ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ປັດຂຶ້ນໂດຍໃຊ້ມືສາມນິ້ວຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ດີຫຼາຍ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"ປັດຂຶ້ນດ້ວຍສາມນິ້ວເທິງແຜ່ນສຳຜັດຂອງທ່ານເພື່ອໄປຫາໂຮມສະກຣີນຂອງທ່ານ"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ເບິ່ງແອັບຫຼ້າສຸດ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ປັດຂຶ້ນໂດຍໃຊ້ມືສາມນິ້ວແລ້ວຄ້າງໄວ້ຢູ່ແຜ່ນສໍາຜັດຂອງທ່ານ"</string> <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> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບທັງໝົດສຳເລັດແລ້ວ"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານເພື່ອເບິ່ງແອັບທັງໝົດຂອງທ່ານ"</string> <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> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 91e17a71eaa3..bfdd89fe1c4a 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Palydovas, pasiekiamas ryšys"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Prisijungimas prie palydovo kritiniu atveju"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Skambučiai pagalbos numeriu arba pagalbos iškvietimas kritiniu atveju"</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">"nėra signalo"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"viena juosta"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dvi juostos"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"trys juostos"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"keturios juostos"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"stiprus signalas"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Darbo profilis"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Smagu, bet ne visada"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sistemos naudotojo sąsajos derinimo priemonė suteikia papildomų galimybių pagerinti ir tinkinti „Android“ naudotojo sąsają. Šios eksperimentinės funkcijos gali pasikeisti, nutrūkti ar išnykti iš būsimų laidų. Tęskite atsargiai."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Pateikti atsiliepimą apie rinkinį"</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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Užrakinti ekraną"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Sukurti pastabą"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Kelių užduočių atlikimas"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Naudokite išskaidyto ekrano režimą su programa dešinėje"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Naudokite išskaidyto ekrano režimą su programa kairėje"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Perjunkite į viso ekrano režimą"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Perjunkite į programą dešinėje arba apačioje išskaidyto ekrano režimu"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Perjunkite į programą kairėje arba viršuje išskaidyto ekrano režimu"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Išskaidyto ekrano režimu: pakeisti iš vienos programos į kitą"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Įjungimo meniu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Užrakinimo ekranas"</string> - <string name="finder_active" msgid="7907846989716941952">"Šį telefoną galite rasti naudodami programą „Rasti įrenginį“, net jei jis išjungtas"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Išjungiama…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Žr. priežiūros veiksmus"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Eikite į pagrindinį puslapį"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Peržiūrėti naujausias programas"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Atlikta"</string> + <string name="gesture_error_title" msgid="469064941635578511">"Bandykite dar kartą!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Braukite kairėn arba dešinėn trimis pirštais bet kur jutiklinėje dalyje"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Šaunu!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Atlikote grįžimo atgal gestą."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"Jei norite grįžti naudodami jutiklinę dalį, perbraukite kairėn arba dešinėn trimis pirštais"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Eikite į pagrindinį ekraną"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Braukite viršun trimis pirštais bet kur jutiklinėje dalyje"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Puiku!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Atlikote perėjimo į pagrindinį ekraną gestą"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"Perbraukite viršun trimis pirštais jutiklinėje dalyje, kad pereitumėte į pagrindinį ekraną"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Peržiūrėti naujausias programas"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Braukite viršun trimis pirštais bet kur jutiklinėje dalyje ir palaikykite"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Puiku!"</string> <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="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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Atlikote visų programų peržiūros gestą"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"Paspauskite klaviatūros veiksmų klavišą, kad peržiūrėtumėte visas programas"</string> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Mokomoji animacija. Spustelėkite, kad pristabdytumėte ir tęstumėte atkūrimą."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index c06c2bad6bbc..9208c7efb0ca 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Poga “Rādīt ekrānsaudzētāju”"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelīts, ir pieejams savienojums"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelīta SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Ārkārtas izsaukumi vai ārkārtas zvani"</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">"nav signāla"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"viena josla"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"divas joslas"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"trīs joslas"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"četras joslas"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"pilna piekļuve signālam"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Darba profils"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Jautri dažiem, bet ne visiem"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sistēmas saskarnes regulators sniedz papildu veidus, kā mainīt un pielāgot Android lietotāja saskarni. Nākamajās versijās šīs eksperimentālās funkcijas var tikt mainītas, bojātas vai to darbība var tikt pārtraukta. Turpinot esiet uzmanīgs."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Sniegt atsauksmes par paziņojumu grupu"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloķēt ekrānu"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Izveidot piezīmi"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Vairākuzdevumu režīms"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Izmantot ekrāna sadalīšanu ar lietotni labajā pusē"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Izmantot ekrāna sadalīšanu ar lietotni kreisajā pusē"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Pārslēgšana pilnekrāna režīmā"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pāriet uz lietotni pa labi/lejā, kamēr izmantojat sadalīto ekrānu."</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pāriet uz lietotni pa kreisi/augšā, kamēr izmantojat sadalīto ekrānu."</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ekrāna sadalīšanas režīmā: pārvietot lietotni no viena ekrāna uz otru"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Barošanas izvēlne"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Bloķēšanas ekrāns"</string> - <string name="finder_active" msgid="7907846989716941952">"Lietotni “Atrast ierīci” var izmantot šī tālruņa atrašanās vietas noteikšanai arī tad, ja tālrunis ir izslēgts."</string> <string name="shutdown_progress" msgid="5464239146561542178">"Notiek izslēgšana…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Skatīt apkopes norādījumus"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pāriet uz sākuma ekrānu"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Skatīt nesen izmantotās lietotnes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gatavs"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Skārienpaliktnī ar trīs pirkstiem velciet pa kreisi vai pa labi."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Lieliski!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Jūs sekmīgi veicāt atgriešanās žestu."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pāreja uz sākuma ekrānu"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Skārienpaliktnī ar trīs pirkstiem velciet augšup."</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Lieliski!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Nesen izmantoto lietotņu skatīšana"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Lieliski!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jūs sekmīgi veicāt nesen izmantoto lietotņu skatīšanas žestu."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Lieliski!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jūs sekmīgi veicāt visu lietotņu skatīšanas žestu."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Mācību animācija. Noklikšķiniet, lai pārtrauktu un atsāktu atskaņošanu."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index a1e6017b0b84..15f24353bc61 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Копче за прикажување на штедачот на екран"</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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Отвори ги поставките за известувања"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Нема известувања}=1{Известувањата ги паузираше {mode}}=2{Известувањата ги паузираа {mode} и уште еден режим}one{Известувањата ги паузираа {mode} и уште # режим}other{Известувањата ги паузираа {mode} и уште # режими}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string> @@ -755,6 +753,13 @@ <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="828510231597991206">"Итни повици или 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">"една цртичка"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"две цртички"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"три цртички"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"четири цртички"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"полн сигнал"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Работен профил"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Забава за некои, но не за сите"</string> <string name="tuner_warning" msgid="1861736288458481650">"Адаптерот на УИ на системот ви дава дополнителни начини за дотерување и приспособување на корисничкиот интерфејс на Android. Овие експериментални функции можеби ќе се изменат, расипат или ќе исчезнат во следните изданија. Продолжете со претпазливост."</string> @@ -788,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Испрати повратни информации за пакет"</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> @@ -874,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Користете поделен екран со апликацијата оддесно"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Користете поделен екран со апликацијата одлево"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Префрлете се на цел екран"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Префрлете се на апликацијата десно или долу при користењето поделен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Префрлете се на апликацијата лево или горе при користењето поделен екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"При поделен екран: префрлете ги аплик. од едната на другата страна"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени на копчето за вклучување"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Заклучен екран"</string> - <string name="finder_active" msgid="7907846989716941952">"Може да го лоцирате телефонов со „Најди го мојот уред“ дури и кога е исклучен"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Се исклучува…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Прикажи ги чекорите за грижа за уредот"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Оди на почетниот екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прикажи ги неодамнешните апликации"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Повлечете налево или надесно со три прста на допирната подлога"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Одлично!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Го научивте движењето за враќање назад."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Одете на почетниот екран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Повлечете нагоре со три прсти на допирната подлога"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Одлично!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Го завршивте движењето за враќање на почетниот екран"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прикажи ги неодамнешните апликации"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Повлечете нагоре и задржете со три прста на допирната подлога"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Го завршивте движењето за прегледување на неодамнешните апликации."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Го завршивте движењето за прегледување на сите апликации"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 4dc40f834449..0f8417e82ec3 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -531,7 +531,7 @@ <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="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"സ്ക്രീൻ സേവർ കാണിക്കുക ബട്ടൺ"</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> @@ -753,6 +753,13 @@ <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="828510231597991206">"എമർജൻസി കോൾ അല്ലെങ്കിൽ 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">"ഒരു ബാർ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"രണ്ട് ബാറുകൾ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"മൂന്ന് ബാറുകൾ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"നാല് ബാറുകൾ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"മികച്ച സിഗ്നൽ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ചിലർക്ക് വിനോദം, എന്നാൽ എല്ലാവർക്കുമില്ല"</string> <string name="tuner_warning" msgid="1861736288458481650">"Android ഉപയോക്തൃ ഇന്റർഫേസ് ആവശ്യമുള്ള രീതിയിൽ മാറ്റുന്നതിനും ഇഷ്ടാനുസൃതമാക്കുന്നതിനും സിസ്റ്റം UI ട്യൂണർ നിങ്ങൾക്ക് അധിക വഴികൾ നൽകുന്നു. ഭാവി റിലീസുകളിൽ ഈ പരീക്ഷണാത്മക ഫീച്ചറുകൾ മാറ്റുകയോ നിർത്തുകയോ അപ്രത്യക്ഷമാവുകയോ ചെയ്തേക്കാം. ശ്രദ്ധയോടെ മുന്നോട്ടുപോകുക."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ബണ്ടിൽ ഫീഡ്ബാക്ക് നൽകുക"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"വലതുവശത്തുള്ള ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ഇടതുവശത്തുള്ള ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറുക"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ വലതുവശത്തെ/താഴത്തെ ആപ്പിലേക്ക് മാറുക"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ ഇടതുവശത്തെ/മുകളിലെ ആപ്പിലേക്ക് മാറൂ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"സ്ക്രീൻ വിഭജന മോഡിൽ: ഒരു ആപ്പിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറുക"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"പവർ മെനു"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ലോക്ക് സ്ക്രീൻ"</string> - <string name="finder_active" msgid="7907846989716941952">"ഓഫായിരിക്കുമ്പോഴും Find My Device ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഈ ഫോൺ കണ്ടെത്താനാകും"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ഷട്ട്ഡൗൺ ചെയ്യുന്നു…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ഹോമിലേക്ക് പോകുക"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"പൂർത്തിയായി"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"കൊള്ളാം!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ഹോമിലേക്ക് പോകൂ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"കൊള്ളാം!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ഹോം ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"കൊള്ളാം!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക എന്ന ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\'എല്ലാ ആപ്പുകളും കാണുക\' ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 13436343e0c4..47a546894d8b 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Дэлгэц амраагчийг харуулах товч"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"Яаралтай дуудлага эсвэл 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">"нэг шон"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"хоёр шон"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"гурван шон"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"дөрвөн шон"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"дохио дүүрэн"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Ажлын профайл"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Зарим хүнд хөгжилтэй байж болох ч бүх хүнд тийм биш"</string> <string name="tuner_warning" msgid="1861736288458481650">"Системийн UI Tохируулагч нь Android хэрэглэгчийн интерфэйсийг тааруулах, өөрчлөх нэмэлт аргыг зааж өгөх болно. Эдгээр туршилтын тохиргоо нь цаашид өөрчлөгдөх, эвдрэх, алга болох магадлалтай. Үйлдлийг болгоомжтой хийнэ үү."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Багц санал хүсэлт өгөх"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Аппыг баруун талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Аппыг зүүн талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Бүтэн дэлгэц рүү сэлгэх"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Дэлгэц хуваахыг ашиглаж байхдаа баруун талд эсвэл доор байх апп руу сэлгэ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Дэлгэц хуваахыг ашиглаж байхдаа зүүн талд эсвэл дээр байх апп руу сэлгэ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Дэлгэц хуваах үеэр: аппыг нэгээс нөгөөгөөр солих"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Асаах/унтраах цэс"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Түгжээтэй дэлгэц"</string> - <string name="finder_active" msgid="7907846989716941952">"Та энэ утсыг унтраалттай байсан ч Миний төхөөрөмжийг олохоор байршлыг нь тогтоох боломжтой"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Унтрааж байна…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Хянамж болгоомжийн алхмыг харах"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Нүүр хуудас руу очих"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Саяхны аппуудыг харах"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Болсон"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Мэдрэгч самбар дээрээ гурван хуруугаа ашиглан зүүн эсвэл баруун тийш шударна уу"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Янзтай!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Та буцах зангааг гүйцэтгэлээ."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Үндсэн нүүр лүү очих"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Мэдрэгч самбар дээрээ гурван хуруугаараа дээш шударна уу"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Үнэхээр сайн ажиллалаа!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Та үндсэн нүүр лүү очих зангааг гүйцэтгэлээ"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Саяхны аппуудыг харах"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Мэдрэгч самбар дээрээ гурван хуруугаа ашиглан дээш шудраад, удаан дарна уу"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Сайн байна!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Та саяхны аппуудыг харах зангааг гүйцэтгэсэн."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Та бүх аппыг харах зангааг гүйцэтгэлээ"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d-с %1$d-р түвшин"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 3f902d4e4ebe..b5c298b3a257 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"स्क्रीनसेव्हर दाखवा बटण"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"आणीबाणी कॉल किंवा 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">"एक बार"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"दोन बार"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"तीन बार"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"चार बार"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"पूर्ण सिग्नल"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string> <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्याला Android यूझर इंटरफेस ट्विक आणि कस्टमाइझ करण्याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्यातील रिलीज मध्ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"बंडलसंबंधित फीडबॅक द्या"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ॲप उजवीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ॲप डावीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"फुल स्क्रीनवर स्विच करणे"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन वापरताना उजवीकडील किंवा खालील अॅपवर स्विच करा"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन वापरताना डावीकडील किंवा वरील अॅपवर स्विच करा"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रीनदरम्यान: एक अॅप दुसऱ्या अॅपने बदला"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पॉवर मेनू"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g> पेज"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्क्रीन"</string> - <string name="finder_active" msgid="7907846989716941952">"तुम्ही हा फोन बंद असतानादेखील Find My Device वापरून तो शोधू शकता"</string> <string name="shutdown_progress" msgid="5464239146561542178">"बंद होत आहे…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"काय काळजी घ्यावी ते पहा"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होमवर जा"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"अलीकडील अॅप्स पहा"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"पूर्ण झाले"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"तुमच्या टचपॅडवर तीन बोटांनी डावीकडे किंवा उजवीकडे स्वाइप करा"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"छान!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"तुम्ही गो बॅक जेश्चर पूर्ण केले."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होमवर जा"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करा"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"उत्तम कामगिरी!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"तुम्ही गो होम जेश्चर पूर्ण केले आहे"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"अलीकडील अॅप्स पहा"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करून धरून ठेवा"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"उत्तम कामगिरी!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तुम्ही अलीकडील ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तुम्ही ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d पैकी %1$d पातळी"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 0900288bd13f..481f6628d0f0 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, sambungan tersedia"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Panggilan kecemasan atau 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">"tiada isyarat"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"satu bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dua bar"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tiga bar"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"empat bar"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"isyarat penuh"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil kerja"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Menarik untuk sesetengah orang tetapi bukan untuk semua"</string> <string name="tuner_warning" msgid="1861736288458481650">"Penala UI Sistem memberi anda cara tambahan untuk mengolah dan menyesuaikan antara muka Android. Ciri eksperimen ini boleh berubah, rosak atau hilang dalam keluaran masa hadapan. Teruskan dengan berhati-hati."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Berikan Maklum Balas Himpunan"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci skrin"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Catat nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Berbilang tugas"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gunakan skrin pisah dengan apl pada sebelah kanan"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gunakan skrin pisah dengan apl pada sebelah kiri"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Beralih kepada skrin penuh"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Tukar kepada apl di sebelah kanan/bawah semasa menggunakan skrin pisah"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Tukar kepada apl di sebelah kiri/atas semasa menggunakan skrin pisah"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Semasa skrin pisah: gantikan apl daripada satu apl kepada apl lain"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu kuasa"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Kunci skrin"</string> - <string name="finder_active" msgid="7907846989716941952">"Anda boleh mengesan telefon ini dengan Find My Device walaupun apabila telefon ini dimatikan kuasa"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Mematikan…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah penjagaan"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Akses laman utama"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat apl terbaharu"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Leret ke kiri atau ke kanan menggunakan tiga jari pada pad sentuh"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bagus!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Anda telah melengkapkan gerak isyarat kembali."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Akses laman utama"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Leret ke atas dengan tiga jari pada pad sentuh anda"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bagus!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Anda telah melengkapkan gerak isyarat akses laman utama"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Lihat apl terbaharu"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Leret ke atas dan tahan menggunakan tiga jari pada pad sentuh"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Syabas!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah melengkapkan gerak isyarat lihat apl terbaharu."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah melengkapkan gerak isyarat lihat semua apl"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animasi tutorial, klik untuk menjeda dan menyambung semula main."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 186b60f7b266..bde5f576f322 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ရနိုင်သည်"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"အရေးပေါ်ဖုန်းခေါ်ခြင်း (သို့) 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">"တစ်ဘား"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"နှစ်ဘား"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"သုံးဘား"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"လေးဘား"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"လိုင်းအပြည့်ရှိသည်"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"အလုပ် ပရိုဖိုင်"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"အချို့သူများ အတွက် ပျော်စရာ ဖြစ်ပေမဲ့ အားလုံး အတွက် မဟုတ်ပါ"</string> <string name="tuner_warning" msgid="1861736288458481650">"စနစ် UI Tuner က သင့်အတွက် Android အသုံးပြုသူ အင်တာဖေ့စ်ကို ပြောင်းရန်နှင့် စိတ်ကြိုက်ပြုလုပ်ရန် နည်းလမ်း အပိုများကို သင့်အတွက် စီစဉ်ပေးသည်။ အနာဂတ်ဗားရှင်းများတွင် ဤစမ်းသပ်အင်္ဂါရပ်များမှာ ပြောင်းလဲ၊ ပျက်စီး သို့မဟုတ် ပျောက်ကွယ်သွားနိုင်သည်။ သတိဖြင့် ရှေ့ဆက်ပါ။"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"အတွဲလိုက် အကြံပြုချက်ပေးရန်"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"အက်ပ်ကို ညာ၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"အက်ပ်ကို ဘယ်၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ဖန်သားပြင်အပြည့် ပြောင်းခြင်း"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"မျက်နှာပြင်ခွဲ၍ပြသခြင်း သုံးစဉ် ညာ (သို့) အောက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးစဉ် ဘယ် (သို့) အထက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"မျက်နှာပြင် ခွဲ၍ပြသစဉ်- အက်ပ်တစ်ခုကို နောက်တစ်ခုနှင့် အစားထိုးရန်"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ပါဝါမီနူး"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်မျက်နှာပြင်"</string> - <string name="finder_active" msgid="7907846989716941952">"ပါဝါပိတ်ထားသော်လည်း Find My Device ဖြင့် ဤဖုန်းကို ရှာနိုင်သည်"</string> <string name="shutdown_progress" msgid="5464239146561542178">"စက်ပိတ်နေသည်…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ပင်မစာမျက်နှာသို့ သွားရန်"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"မကြာသေးမီကအက်ပ်များကို ကြည့်ရန်"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ပြီးပြီ"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ပြန်သွားရန်"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ကောင်းပါသည်။"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"နောက်သို့လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ပင်မစာမျက်နှာသို့ သွားရန်"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"တာ့ချ်ပက်ပေါ်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ ပွတ်ဆွဲပါ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"တော်ပါပေသည်။"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်း"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"သင့်တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"တော်ပါပေသည်။"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ။"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"အက်ပ်အားလုံးကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"အဆင့် %2$d အနက် %1$d"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 1ef544b5473e..9dd0f99397c4 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Knapp for å vise skjermspareren"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitt – tilkobling tilgjengelig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-alarm via satellitt"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nødanrop eller 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">"ikke noe signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"én strek"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"to streker"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tre streker"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"fire streker"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"full signalstyrke"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Work-profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Gøy for noen – ikke for alle"</string> <string name="tuner_warning" msgid="1861736288458481650">"Med System UI Tuner har du flere måter å justere og tilpasse Android-brukergrensesnittet på. Disse eksperimentelle funksjonene kan endres, avbrytes eller fjernes i fremtidige utgivelser. Fortsett med forbehold."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Gi tilbakemelding om pakken"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Låseskjerm"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Ta et notat"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Bruk delt skjerm med appen til høyre"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Bruk delt skjerm med appen til venstre"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Bytt til fullskjerm"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bytt til appen til høyre eller under mens du bruker delt skjerm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bytt til appen til venstre eller over mens du bruker delt skjerm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"I delt skjerm: Bytt ut en app"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Av/på-meny"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskjerm"</string> - <string name="finder_active" msgid="7907846989716941952">"Du kan finne denne telefonen med Finn enheten min, selv når den er slått av"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Slår av …"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se hva du kan gjøre"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se hva du kan gjøre"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se nylige apper"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Ferdig"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Sveip til venstre eller høyre med tre fingre på styreflaten"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bra!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du har fullført bevegelsen for å gå tilbake."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Gå til startsiden"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Sveip opp med tre fingre på styreflaten"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bra jobbet!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du har fullført bevegelsen for å gå til startskjermen"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se nylige apper"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Sveip opp og hold med tre fingre på styreflaten"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbet!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har fullført bevegelsen for å se nylige apper."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har fullført bevegelsen for å se alle apper"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Veiledningsanimasjon. Klikk for å sette avspillingen på pause og gjenoppta den."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 9a97010037d1..968fd518f068 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"आपत्कालीन कल वा 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">"एउटा बार"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"दुई वटा बार"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"तीन वटा बार"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"चार वटा बार"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"पूरै सिग्नल छ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाइल"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"केहीका लागि रमाइलो हुन्छ तर सबैका लागि होइन"</string> <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनरले तपाईँलाई Android प्रयोगकर्ता इन्टरफेस कस्टम गर्न र ट्विक गर्न थप तरिकाहरू प्रदान गर्छ। यी प्रयोगात्मक सुविधाहरू भावी विमोचनमा परिवर्तन हुन, बिग्रिन वा हराउन सक्ने छन्। सावधानीपूर्वक अगाडि बढ्नुहोस्।"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"बन्डलका बारेमा प्रतिक्रिया दिनुहोस्"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"हालको एप दायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"हालको एप बायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"फुल स्क्रिन प्रयोग गर्नुहोस्"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा दायाँ वा तलको एप चलाउनुहोस्"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा बायाँ वा माथिको एप चलाउनुहोस्"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"स्प्लिट स्क्रिन प्रयोग गरिएका बेला: एउटा स्क्रिनमा भएको एप अर्कोमा लैजानुहोस्"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेनु"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"लक स्क्रिन"</string> - <string name="finder_active" msgid="7907846989716941952">"तपाईं Find My Device प्रयोग गरी यो फोन अफ भए पनि यसको लोकेसन पत्ता लगाउन सक्नुहुन्छ"</string> <string name="shutdown_progress" msgid="5464239146561542178">"सट डाउन गरिँदै छ..."</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रिनमा जानुहोस्"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"सम्पन्न भयो"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"तीन वटा औँला प्रयोग गरी टचप्याडमा बायाँ वा दायाँतिर स्वाइप गर्नुहोस्"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"राम्रो!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"तपाईंले जेस्चर प्रयोग गरी पछाडि जाने तरिका सिक्नुभएको छ।"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"होमपेजमा जानुहोस्"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"टचप्याडमा तीन वटा औँलाले माथितिर स्वाइप गर्नुहोस्"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"अद्भुत!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"तीन वटा औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"अद्भुत!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तपाईंले जेस्चर प्रयोग गरी हालसालै चलाइएका एपहरू हेर्ने तरिका सिक्नुभएको छ।"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तपाईंले जेस्चर प्रयोग गरी सबै एपहरू हेर्ने तरिका सिक्नुभएको छ"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d मध्ये %1$d औँ स्तर"</string> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index c1eff5f629b3..a77f5e4629c1 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -108,6 +108,9 @@ <color name="people_tile_background">@color/material_dynamic_secondary20</color> + <!-- Dark Theme colors for notification shade/scrim --> + <color name="shade_panel">@android:color/system_accent1_900</color> + <!-- Keyboard shortcut helper dialog --> <color name="ksh_key_item_color">@*android:color/system_on_surface_variant_dark</color> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index e7fe53660aa2..adc157b31eb2 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding beschikbaar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satelliet"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Noodoproepen of 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">"geen signaal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"1 streepje"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 streepjes"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 streepjes"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 streepjes"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signaal op volledige sterkte"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Werkprofiel"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Leuk voor sommige gebruikers, maar niet voor iedereen"</string> <string name="tuner_warning" msgid="1861736288458481650">"Met Systeem-UI-tuner beschikt u over extra manieren om de Android-gebruikersinterface aan te passen. Deze experimentele functies kunnen veranderen, vastlopen of verdwijnen in toekomstige releases. Ga voorzichtig verder."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Feedback over bundel geven"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Scherm vergrendelen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Notitie maken"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasken"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gesplitst scherm gebruiken met de app aan de rechterkant"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gesplitst scherm gebruiken met de app aan de linkerkant"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Overschakelen naar volledig scherm"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Naar de app rechts of onderaan gaan als je een gesplitst scherm gebruikt"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Naar de app links of bovenaan gaan als je een gesplitst scherm gebruikt"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijdens gesplitst scherm: een app vervangen door een andere"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/uit-menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelscherm"</string> - <string name="finder_active" msgid="7907846989716941952">"Je kunt deze telefoon vinden met Vind mijn apparaat, ook als die uitstaat"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Uitzetten…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Onderhoudsstappen bekijken"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Naar startscherm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Recente apps bekijken"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swipe met 3 vingers naar links of rechts op de touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Goed zo!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Je weet nu hoe je het gebaar voor terug maakt."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Naar startscherm"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swipe met 3 vingers omhoog op de touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Goed gedaan!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Je weet nu hoe je het gebaar Naar startscherm maakt"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Recente apps bekijken"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swipe met 3 vingers omhoog en houd vast op de touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Goed gedaan!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Je weet nu hoe je het gebaar Recente apps bekijken maakt."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Je weet nu hoe je het gebaar Alle apps bekijken maakt"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial-animatie, klik om het afspelen te onderbreken en te hervatten."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 35704ea2fcaa..12a13ff65968 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"ଜରୁରୀକାଳୀନ କଲ କିମ୍ବା 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">"ଗୋଟିଏ ବାର"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ଦୁଇଟି ବାର"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"ତିନୋଟି ବାର"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ଚାରୋଟି ବାର"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ସିଗନାଲ ପୂର୍ଣ୍ଣ ଅଛି"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"କେତେକଙ୍କ ପାଇଁ ମଜାଦାର, କିନ୍ତୁ ସମସ୍ତଙ୍କ ପାଇଁ ନୁହେଁ"</string> <string name="tuner_warning" msgid="1861736288458481650">"Android ୟୁଜର୍ ଇଣ୍ଟରଫେସ୍ ବଦଳାଇବାକୁ ତଥା ନିଜ ପସନ୍ଦ ଅନୁଯାୟୀ କରିବାକୁ ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍ ଆପଣଙ୍କୁ ଅତିରିକ୍ତ ଉପାୟ ପ୍ରଦାନ କରେ। ଏହି ପରୀକ୍ଷାମୂଳକ ସୁବିଧାମାନ ବଦଳିପାରେ, ଭାଙ୍ଗିପାରେ କିମ୍ବା ଭବିଷ୍ୟତର ରିଲିଜ୍ଗୁଡ଼ିକରେ ନଦେଖାଯାଇପାରେ। ସତର୍କତାର ସହ ଆଗକୁ ବଢ଼ନ୍ତୁ।"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ବଣ୍ଡଲ ମତାମତ ପ୍ରଦାନ କରନ୍ତୁ"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ଡାହାଣରେ ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ବାମରେ ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ଡାହାଣପଟର ବା ତଳର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ବାମପଟର ବା ଉପରର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ସମୟରେ: କୌଣସି ଆପକୁ ଗୋଟିଏରୁ ଅନ୍ୟ ଏକ ଆପରେ ବଦଳାନ୍ତୁ"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ପାୱାର ମେନୁ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"ଲକ ସ୍କ୍ରିନ"</string> - <string name="finder_active" msgid="7907846989716941952">"ପାୱାର ବନ୍ଦ ଥିଲେ ମଧ୍ୟ ଆପଣ Find My Device ମାଧ୍ୟମରେ ଏହି ଫୋନକୁ ଖୋଜିପାରିବେ"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ବନ୍ଦ କରାଯାଉଛି…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ହୋମକୁ ଯାଆନ୍ତୁ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ହୋଇଗଲା"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ବଢ଼ିଆ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ହୋମକୁ ଯାଆନ୍ତୁ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ବଢ଼ିଆ କାମ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ବର୍ତ୍ତମାନର ଆପ୍ସକୁ ଭ୍ୟୁ କରନ୍ତୁ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିକୁ ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ବଢ଼ିଆ କାମ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ଆପଣ ସମସ୍ତ ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 68cd2b42f069..feaae0eb50af 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"\'ਸਕ੍ਰੀਨ-ਸੇਵਰ ਦਿਖਾਓ\' ਬਟਨ"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ ਜਾਂ ਸਹਾਇਤਾ"</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">"ਇੱਕ ਸਿਗਨਲ ਪੱਟੀ"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ਦੋ ਸਿਗਨਲ ਪੱਟੀਆਂ"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"ਤਿੰਨ ਸਿਗਨਲ ਪੱਟੀਆਂ"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"ਚਾਰ ਸਿਗਨਲ ਪੱਟੀਆਂ"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"ਪੂਰਾ ਸਿਗਨਲ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"ਕੁਝ ਵਾਸਤੇ ਤਾਂ ਮਜ਼ੇਦਾਰ ਹੈ ਲੇਕਿਨ ਸਾਰਿਆਂ ਵਾਸਤੇ ਨਹੀਂ"</string> <string name="tuner_warning" msgid="1861736288458481650">"ਸਿਸਟਮ UI ਟਿਊਨਰ ਤੁਹਾਨੂੰ Android ਵਰਤੋਂਕਾਰ ਇੰਟਰਫ਼ੇਸ ਤਬਦੀਲ ਕਰਨ ਅਤੇ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਵਾਧੂ ਤਰੀਕੇ ਦਿੰਦਾ ਹੈ। ਇਹ ਪ੍ਰਯੋਗਾਤਮਿਕ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਭਵਿੱਖ ਦੀ ਰੀਲੀਜ਼ ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਟੁੱਟ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਸਾਵਧਾਨੀ ਨਾਲ ਅੱਗੇ ਵੱਧੋ।"</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"ਬੰਡਲ ਬਾਰੇ ਵਿਚਾਰ ਮੁਹੱਈਆ ਕਰਵਾਓ"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ਸੱਜੇ ਪਾਸੇ ਵਾਲੀ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ਖੱਬੇ ਪਾਸੇ ਵਾਲੀ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ਪੂਰੀ-ਸਕ੍ਰੀਨ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਸੱਜੇ ਜਾਂ ਹੇਠਾਂ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਖੱਬੇ ਜਾਂ ਉੱਪਰ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੌਰਾਨ: ਇੱਕ ਐਪ ਨਾਲ ਦੂਜੀ ਐਪ ਨੂੰ ਬਦਲੋ"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ਪਾਵਰ ਮੀਨੂ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">" ਲਾਕ ਸਕ੍ਰੀਨ"</string> - <string name="finder_active" msgid="7907846989716941952">"ਬੰਦ ਹੋਣ \'ਤੇ ਵੀ, ਤੁਸੀਂ ਇਸ ਫ਼ੋਨ ਨੂੰ Find My Device ਦੀ ਮਦਦ ਨਾਲ ਲੱਭ ਸਕਦੇ ਹੋ"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ਬੰਦ ਹੋ ਰਿਹਾ ਹੈ…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ਹੋਮ \'ਤੇ ਜਾਓ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ਹੋ ਗਿਆ"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ਵਧੀਆ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ਹੋਮ \'ਤੇ ਜਾਓ"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਨਾਲ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"ਬਹੁਤ ਵਧੀਆ!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ਬਹੁਤ ਵਧੀਆ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ਤੁਸੀਂ \'ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ।"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ਤੁਸੀਂ \'ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index a970e2891e61..bd7496d128f2 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelita – połączenie dostępne"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelitarne połączenie alarmowe"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Połączenia alarmowe lub 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">"brak sygnału"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"1 pasek"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 paski"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 paski"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 paski"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"pełna moc sygnału"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil służbowy"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Dobra zabawa, ale nie dla każdego"</string> <string name="tuner_warning" msgid="1861736288458481650">"Kalibrator System UI udostępnia dodatkowe sposoby dostrajania i dostosowywania interfejsu Androida. Te eksperymentalne funkcje mogą się zmienić, popsuć lub zniknąć w przyszłych wersjach. Zachowaj ostrożność."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Prześlij opinię o pakiecie"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Zablokuj ekran"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Zanotuj"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Wielozadaniowość"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Podziel ekran z aplikacją widoczną po prawej"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Podziel ekran z aplikacją widoczną po lewej"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Włącz pełny ekran"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Przełącz się na aplikację po prawej lub poniżej na podzielonym ekranie"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Przełącz się na aplikację po lewej lub powyżej na podzielonym ekranie"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Podczas podzielonego ekranu: zastępowanie aplikacji"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu zasilania"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran blokady"</string> - <string name="finder_active" msgid="7907846989716941952">"Możesz zlokalizować ten telefon w usłudze Znajdź moje urządzenie, nawet jeśli będzie wyłączony"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Wyłączam…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobacz instrukcję postępowania"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Otwórz stronę główną"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Wyświetlanie ostatnich aplikacji"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotowe"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Przesuń 3 palcami w prawo lub w lewo na touchpadzie"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Super!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Gest przejścia wstecz został opanowany."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Otwórz stronę główną"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Przesuń 3 palcami w górę na touchpadzie"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Dobra robota!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Gest przechodzenia na ekran główny został opanowany"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Wyświetlanie ostatnich aplikacji"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Przesuń w górę za pomocą 3 palców na touchpadzie i przytrzymaj"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Brawo!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Znasz już gest wyświetlania ostatnio używanych aplikacji."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Brawo!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Znasz już gest wyświetlania wszystkich aplikacji"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacja z samouczkiem. Kliknij, aby wstrzymać lub wznowić odtwarzanie."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index f28de4ecc2fa..b2db1208f0f6 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botão \"Mostrar protetor de tela\""</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou 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">"sem sinal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"duas barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"três barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"quatro barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinal máximo"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string> <string name="tuner_warning" msgid="1861736288458481650">"O sintonizador System UI fornece maneiras adicionais de ajustar e personalizar a interface do usuário do Android. Esses recursos experimentais podem mudar, falhar ou desaparecer nas versões futuras. Prossiga com cuidado."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar feedback sobre o pacote"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Criar nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefas"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar a tela dividida com o app à direita"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar a tela dividida com o app à esquerda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Mudar para tela cheia"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string> - <string name="finder_active" msgid="7907846989716941952">"Localize o smartphone com o Encontre Meu Dispositivo mesmo se ele estiver desligado"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Desligando…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize para a esquerda ou direita com 3 dedos no touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Legal!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Você concluiu o gesto para voltar."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir para a página inicial"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima com 3 dedos e mantenha"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animação do tutorial. Clique para pausar ou retomar a reprodução."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 83aa9cf35d8f..dcc8f02e666c 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, ligação disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satélite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou 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">"sem sinal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"1 barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinal completo"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string> <string name="tuner_warning" msgid="1861736288458481650">"O Sintonizador da interface do sistema disponibiliza-lhe formas adicionais ajustar e personalizar a interface do utilizador do Android. Estas funcionalidades experimentais podem ser alteradas, deixar de funcionar ou desaparecer em versões futuras. Prossiga com cuidado."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar feedback sobre o pacote"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Ecrã de bloqueio"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Tire notas"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Execução de várias tarefas em simultâneo"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Use o ecrã dividido com a app à direita"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Use o ecrã dividido com a app à esquerda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Mude para ecrã inteiro"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para a app à direita ou abaixo enquanto usa o ecrã dividido"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para a app à esquerda ou acima enquanto usa o ecrã dividido"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante o ecrã dividido: substituir uma app por outra"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu ligar/desligar"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ecrã de bloqueio"</string> - <string name="finder_active" msgid="7907846989716941952">"Pode localizar este telemóvel com o serviço Localizar o meu dispositivo mesmo quando está desligado"</string> <string name="shutdown_progress" msgid="5464239146561542178">"A encerrar…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Veja os passos de manutenção"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Aceder ao ecrã principal"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluir"</string> + <string name="gesture_error_title" msgid="469064941635578511">"Tente novamente!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize rapidamente para a esquerda ou direita com 3 dedos no touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Boa!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Concluiu o gesto para retroceder."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"Para retroceder com o touchpad, deslize rapidamente para a esquerda ou direita com 3 dedos"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Aceder ao ecrã principal"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"É assim mesmo!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Concluiu o gesto para aceder ao ecrã principal"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"Deslize rapidamente para cima com 3 dedos no touchpad para aceder ao ecrã principal"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver apps recentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize rapidamente para cima sem soltar com 3 dedos no touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <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="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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Concluiu o gesto para ver todas as apps"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"Prima a tecla de ação no teclado para ver todas as suas apps"</string> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animação do tutorial, clique para pausar e retomar a reprodução."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index f28de4ecc2fa..b2db1208f0f6 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botão \"Mostrar protetor de tela\""</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Chamadas de emergência ou 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">"sem sinal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"duas barras"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"três barras"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"quatro barras"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinal máximo"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabalho"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diversão para alguns, mas não para todos"</string> <string name="tuner_warning" msgid="1861736288458481650">"O sintonizador System UI fornece maneiras adicionais de ajustar e personalizar a interface do usuário do Android. Esses recursos experimentais podem mudar, falhar ou desaparecer nas versões futuras. Prossiga com cuidado."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Enviar feedback sobre o pacote"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Criar nota"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefas"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Usar a tela dividida com o app à direita"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Usar a tela dividida com o app à esquerda"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Mudar para tela cheia"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para o app à direita ou abaixo ao usar a tela dividida"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mudar para o app à esquerda ou acima ao usar a tela dividida"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Com a tela dividida: substituir um app por outro"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string> - <string name="finder_active" msgid="7907846989716941952">"Localize o smartphone com o Encontre Meu Dispositivo mesmo se ele estiver desligado"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Desligando…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Deslize para a esquerda ou direita com 3 dedos no touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Legal!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Você concluiu o gesto para voltar."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ir para a página inicial"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Deslize para cima com 3 dedos no touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Muito bem!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Você concluiu o gesto para acessar a tela inicial"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ver os apps recentes"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Deslize para cima com 3 dedos e mantenha"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animação do tutorial. Clique para pausar ou retomar a reprodução."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index ea320a141c6e..7664145cc469 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Butonul Afișează screensaverul"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, conexiune disponibilă"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prin satelit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Apeluri de urgență sau 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">"fără semnal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"o bară"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"două bare"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"trei bare"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"patru bare"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"semnal complet"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil de serviciu"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Distractiv pentru unii, dar nu pentru toată lumea"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner oferă modalități suplimentare de a ajusta și a personaliza interfața de utilizare Android. Aceste funcții experimentale pot să se schimbe, să se blocheze sau să dispară din versiunile viitoare. Continuă cu prudență."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Trimite feedback despre pachet"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Ecranul de blocare"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Creează o notă"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Folosește ecranul împărțit cu aplicația în dreapta"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Folosește ecranul împărțit cu aplicația în stânga"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Treci la ecran complet"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Treci la aplicația din dreapta sau de mai jos cu ecranul împărțit"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Treci la aplicația din stânga sau de mai sus cu ecranul împărțit"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"În modul ecran împărțit: înlocuiește o aplicație cu alta"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meniul de pornire"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ecran de blocare"</string> - <string name="finder_active" msgid="7907846989716941952">"Poți localiza telefonul folosind aplicația Găsește-mi dispozitivul chiar dacă este închis"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Se închide…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vezi pașii pentru îngrijire"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vezi pașii pentru îngrijire"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Înapoi la pagina de pornire"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Vezi aplicațiile recente"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gata"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Glisează la stânga sau la dreapta cu trei degete pe touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bravo!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ai finalizat gestul Înapoi."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Înapoi la pagina de pornire"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Glisează în sus cu trei degete oriunde pe touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Excelent!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ai finalizat gestul „înapoi la pagina de pornire”"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Vezi aplicațiile recente"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Glisează în sus și ține apăsat cu trei degete pe touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Excelent!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ai finalizat gestul pentru afișarea aplicațiilor recente."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Felicitări!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ai finalizat gestul pentru afișarea tuturor aplicațiilor"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animat, dă clic pentru a întrerupe și a relua redarea."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index f78593681f69..19ccb082a203 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Показать заставку\""</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"Экстренные вызовы или спутниковый 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">"одно деление"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"два деления"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"три деления"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"четыре деления"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"надежный сигнал"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Рабочий профиль"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Внимание!"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner позволяет настраивать интерфейс устройства Android по вашему вкусу. В будущем эта экспериментальная функция может измениться, перестать работать или исчезнуть."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Отправить отзыв о сгруппированных уведомлениях"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Разделить экран и поместить открытое приложение справа"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Разделить экран и поместить открытое приложение слева"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Включить полноэкранный режим"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти к приложению справа или внизу на разделенном экране"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Перейти к приложению слева или вверху на разделенном экране"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"В режиме разделения экрана заменить одно приложение другим"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки питания"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокированный экран"</string> - <string name="finder_active" msgid="7907846989716941952">"С помощью приложения \"Найти устройство\" вы можете узнать местоположение телефона, даже когда он выключен."</string> <string name="shutdown_progress" msgid="5464239146561542178">"Выключение…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Подробнее о действиях при перегреве…"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На главный экран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Просмотр недавних приложений"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Проведите тремя пальцами влево или вправо по сенсорной панели."</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Отлично!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Вы выполнили жест для перехода назад."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"На главный экран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Проведите тремя пальцами вверх по сенсорной панели."</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Отлично!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Вы выполнили жест для перехода на главный экран."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Просмотр недавних приложений"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Проведите вверх по сенсорной панели тремя пальцами и удерживайте."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы выполнили жест для просмотра недавних приложений."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы выполнили жест для просмотра всех приложений."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 68cdef71535f..516b2aeb9ce0 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"තිර සුරැකුම් බොත්තම පෙන්වන්න"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"හදිසි ඇමතුම් හෝ 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">"තීරු එකක්"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"තීරු දෙකයි"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"තීරු තුනයි"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"තීරු හතරක්"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"සංඥාව පිරී ඇත"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"කාර්යාල පැතිකඩ"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"සමහරක් දේවල් වලට විනෝදයි, නමුත් සියල්ලටම නොවේ"</string> <string name="tuner_warning" msgid="1861736288458481650">"පද්ධති UI සුසරකය ඔබට Android පරිශීලක අතුරු මුහුණත වෙනස් කිරීමට හෝ අභිරුචිකරණය කිරීමට අමතර ක්රම ලබා දේ. මෙම පර්යේෂණාත්මක අංග ඉදිරි නිකුත් වීම් වල වෙනස් වීමට, වැඩ නොකිරීමට, හෝ නැතිවීමට හැක. ප්රවේශමෙන් ඉදිරියට යන්න."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"බණ්ඩල් ප්රතිපෝෂණ ලබා දෙන්න"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"දකුණේ යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"වම් පැත්තේ යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"සම්පූර්ණ තිරයට මාරු වන්න"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"බෙදුම් තිරය භාවිත කරන අතරතුර දකුණේ හෝ පහළින් ඇති යෙදුමට මාරු වන්න"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"බෙදුම් තිරය භාවිත කරන අතරතුර වමේ හෝ ඉහළ ඇති යෙදුමට මාරු වන්න"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"බෙදුම් තිරය අතරතුර: යෙදුමක් එකකින් තවත් එකක් ප්රතිස්ථාපනය කරන්න"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"බල මෙනුව"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"අගුලු තිරය"</string> - <string name="finder_active" msgid="7907846989716941952">"බලය ක්රියාවිරහිත වූ විට පවා ඔබට මගේ උපාංගය සෙවීම මගින් මෙම දුරකථනය සොයාගත හැක"</string> <string name="shutdown_progress" msgid="5464239146561542178">"වසා දමමින්…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"රැකවරණ පියවර බලන්න"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"මුල් පිටුවට යන්න"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"මෑත යෙදුම් බලන්න"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"නිමයි"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"කදිමයි!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"මුල් පිටුවට යන්න"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ඔබේ ස්පර්ශ පුවරුවේ ඇඟිලි තුනකින් ඉහළට ස්වයිප් කරන්න"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"අනර්ඝ වැඩක්!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"මෑත යෙදුම් බලන්න"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ඉහළට ස්වයිප් කර ඔබේ ස්පර්ශ පුවරුව මත ඇඟිලි තුනක් භාවිත කර රඳවාගෙන සිටින්න"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"අනර්ඝ වැඩක්!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ඔබ මෑත යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ඔබ සියලු යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$dන් %1$d වැනි මට්ටම"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 552b2e362eeb..1b2dc5a22204 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -454,7 +454,7 @@ <string name="zen_mode_off" msgid="1736604456618147306">"Vypnuté"</string> <string name="zen_mode_set_up" msgid="8231201163894922821">"Nenastavené"</string> <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"Správa v nastaveniach"</string> - <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žiadne aktívne režimy}=1{{mode} je aktívny}few{# režimy sú aktívne}many{# modes are active}other{# režimov je aktívnych}}"</string> + <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Žiadne aktívne režimy}=1{Aktívny režim {mode}}few{# aktívne režimy}many{# modes are active}other{# aktívnych režimov}}"</string> <string name="zen_priority_introduction" msgid="3159291973383796646">"Nebudú vás vyrušovať zvuky ani vibrácie, iba budíky, pripomenutia, udalosti a volajúci, ktorých určíte. Budete naďalej počuť všetko, čo sa rozhodnete prehrať, ako napríklad hudbu, videá a hry."</string> <string name="zen_alarms_introduction" msgid="3987266042682300470">"Nebudú vás vyrušovať zvuky ani vibrácie, iba budíky. Budete naďalej počuť všetko, čo sa rozhodnete prehrať, ako napríklad hudbu, videá a hry."</string> <string name="zen_priority_customize_button" msgid="4119213187257195047">"Prispôsobiť"</string> @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Zobraziť tlačidlo šetriča obrazovky"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, pripojenie je k dispozícii"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Pomoc cez satelit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Tiesňové volania alebo pomoc v tiesni"</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">"žiadny signál"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čiarka"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dve čiarky"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tri čiarky"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"štyri čiarky"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"plný signál"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Pracovný profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Pri používaní tuneru postupujte opatrne"</string> <string name="tuner_warning" msgid="1861736288458481650">"Tuner používateľského rozhrania systému poskytujte ďalšie spôsoby ladenia a prispôsobenia používateľského rozhrania Android. Tieto experimentálne funkcie sa môžu v budúcich verziách zmeniť, ich poskytovanie môže byť prerušené alebo môžu byť odstránené. Pokračujte opatrne."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Poskytnúť spätnú väzbu k balíku"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknutie obrazovky"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Napísanie poznámky"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Rozdelenie obrazovky, aktuálna aplikácia vpravo"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Rozdelenie obrazovky, aktuálna aplikácia vľavo"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Prepnutie na celú obrazovku"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prechod na aplikáciu vpravo alebo dole pri rozdelenej obrazovke"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prechod na aplikáciu vľavo alebo hore pri rozdelenej obrazovke"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Počas rozdelenej obrazovky: nahradenie aplikácie inou"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ponuka vypínača"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Uzamknutá obrazovka"</string> - <string name="finder_active" msgid="7907846989716941952">"Pomocou funkcie Nájdi moje zariadenie môžete zistiť polohu tohto telefónu, aj keď je vypnutý"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Vypína sa…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobraziť opatrenia"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Prejsť na plochu"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazenie nedávnych aplikácií"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> - <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> + <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejdenie späť"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Potiahnite troma prstami na touchpade doľava alebo doprava"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Výborne!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Použili ste gesto na prechod späť."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Prechod na plochu"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Potiahnite troma prstami na touchpade nahor"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Skvelé!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Použili ste gesto na prechod na plochu."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Zobrazenie nedávnych aplikácií"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Potiahnite troma prstami na touchpade nahor a pridržte"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Skvelé!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Použili ste gesto na zobrazenie nedávnych aplikácií."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Dobre!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Použili ste gesto na zobrazenie všetkých aplikácií."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Výuková animácia, kliknutím pozastavíte alebo obnovíte prehrávanie."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 33d400ce80cc..76ce78cb9c78 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, povezava je na voljo"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prek satelita"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Klici v sili ali SOS prek satelita"</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">"ni signala"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"ena črtica"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dve črtici"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tri črtice"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"štiri črtice"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"poln signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Delovni profil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Zabavno za nekatere, a ne za vse"</string> <string name="tuner_warning" msgid="1861736288458481650">"Uglaševalnik uporabniškega vmesnika sistema vam omogoča dodatne načine za spreminjanje in prilagajanje uporabniškega vmesnika Android. Te poskusne funkcije lahko v prihodnjih izdajah kadar koli izginejo, se spremenijo ali pokvarijo. Bodite previdni."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Pošiljanje povratnih informacij v paketu"</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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaklepanje zaslona"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Ustvarjanje zapiska"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Večopravilnost"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Uporaba razdeljenega zaslona z aplikacijo na desni"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Uporaba razdeljenega zaslona z aplikacijo na levi"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Preklop na celozaslonski način"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Preklop na aplikacijo desno ali spodaj med uporabo razdeljenega zaslona"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Preklop na aplikacijo levo ali zgoraj med uporabo razdeljenega zaslona"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Pri razdeljenem zaslonu: medsebojna zamenjava aplikacij"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni za vklop/izklop"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaklenjen zaslon"</string> - <string name="finder_active" msgid="7907846989716941952">"S storitvijo Poišči mojo napravo lahko ta telefon poiščete, tudi če je izklopljen"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Zaustavljanje …"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Oglejte si navodila za ukrepanje"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pomik na začetni zaslon"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ogled nedavnih aplikacij"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Končano"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Na sledilni ploščici s tremi prsti povlecite levo ali desno"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Odlično!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Izvedli ste potezo za pomik nazaj."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pomik na začetni zaslon"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Na sledilni ploščici s tremi prsti povlecite navzgor"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Odlično!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Izvedli ste potezo za pomik na začetni zaslon"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Ogled nedavnih aplikacij"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Na sledilni ploščici s tremi prsti povlecite navzgor in pridržite"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvedli ste potezo za ogled nedavnih aplikacij."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvedli ste potezo za ogled vseh aplikacij"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacija v vadnici, kliknite za začasno zaustavitev in nadaljevanje predvajanja."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index ce7c9c0f0af7..dd13cff0e96b 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Shfaq butonin e mbrojtësit të ekranit"</string> <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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Njoftimet"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Pastro të gjitha njoftimet në heshtje"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Hap cilësimet e njoftimeve"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Njoftimet janë vendosur në pauzë nga modaliteti \"Mos shqetëso\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Asnjë njoftim}=1{Njoftimet u vendosën në pauzë nga {mode}}=2{Njoftimet u vendosën në pauzë nga {mode} dhe një modalitet tjetër}other{Njoftimet u vendosën në pauzë nga {mode} dhe # modalitete të tjera}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Fillo tani"</string> @@ -755,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sateliti. Ofrohet lidhje"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satelitor"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Telefonatat e urgjencës ose 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">"nuk ka sinjal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"një vijë"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dy vija"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tre vija"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"katër vija"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"sinjal i plotë"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profili i punës"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Argëtim për disa, por jo për të gjithë!"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit të jep mënyra shtesë për të tërhequr dhe personalizuar ndërfaqen Android të përdoruesit. Këto funksione eksperimentale mund të ndryshojnë, prishen ose zhduken në versionet e ardhshme. Vazhdo me kujdes."</string> @@ -788,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Jep komente për paketën"</string> <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> @@ -874,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Ekrani i kyçjes"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Mbaj një shënim"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Kryerja e shumë detyrave"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Përdor ekranin e ndarë me aplikacionin në të djathtë"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Përdor ekranin e ndarë me aplikacionin në të majtë"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Kalo në ekran të plotë"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Kalo tek aplikacioni djathtas ose poshtë kur përdor ekranin e ndarë"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Kalo tek aplikacioni në të majtë ose sipër kur përdor ekranin e ndarë"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Gjatë ekranit të ndarë: zëvendëso një aplikacion me një tjetër"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyja e energjisë"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekrani i kyçjes"</string> - <string name="finder_active" msgid="7907846989716941952">"Mund ta gjesh këtë telefon me \"Gjej pajisjen time\" edhe kur është i fikur"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Po fiket…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Shiko hapat për kujdesin"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Shko tek ekrani bazë"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Shiko aplikacionet e fundit"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta në bllokun me prekje"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bukur!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"E ke përfunduar gjestin e kthimit prapa."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Shko tek ekrani bazë"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Rrëshqit shpejt lart me tre gishta në bllokun me prekje"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Punë e shkëlqyer!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"E ke përfunduar gjestin e kalimit tek ekrani bazë"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Shiko aplikacionet e fundit"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Punë e shkëlqyer!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Përfundove gjestin për shikimin e aplikacioneve të fundit."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Shumë mirë!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Përfundove gjestin për shikimin e të gjitha aplikacioneve"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animacioni udhëzues. Kliko për të vendosur në pauzë dhe për të vazhduar luajtjen."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 8ae54465d9a7..56939566c012 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, веза је доступна"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хитна помоћ преко сателита"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Хитни позиви или хитна помоћ"</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">"једна црта"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"две црте"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"три црте"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"четири црте"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"сигнал је најјачи"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Пословни профил"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Забава за неке, али не за све"</string> <string name="tuner_warning" msgid="1861736288458481650">"Тјунер за кориснички интерфејс система вам пружа додатне начине за подешавање и прилагођавање Android корисничког интерфејса. Ове експерименталне функције могу да се промене, откажу или нестану у будућим издањима. Будите опрезни."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Пружите повратне информације о скупу"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Користи подељени екран са апликацијом с десне стране"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Користи подељени екран са апликацијом с леве стране"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Пређи на режим преко целог екрана"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пређи у апликацију здесна или испод док је подељен екран"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пређите у апликацију слева или изнад док користите подељени екран"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"У режиму подељеног екрана: замена једне апликације другом"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени дугмета за укључивање"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Закључан екран"</string> - <string name="finder_active" msgid="7907846989716941952">"Можете да лоцирате овај телефон помоћу услуге Пронађи мој уређај чак и када је искључен"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Искључује се…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Погледајте упозорења"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Иди на почетни екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прикажи недавно коришћене апликације"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Превуците улево или удесно са три прста на тачпеду"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Супер!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Довршили сте покрет за повратак."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Иди на почетни екран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Превуците нагоре са три прста на тачпеду"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Одлично!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Довршили сте покрет за повратак на почетну страницу."</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Прикажи недавно коришћене апликације"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Превуците нагоре и задржите са три прста на тачпеду"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Довршили сте покрет за приказивање недавно коришћених апликација."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Довршили сте покрет за приказивање свих апликација."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index dcb1955bc87a..7d1f755c77e5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Visa skärmsläckarknappen"</string> <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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Aviseringar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Rensa alla ljudlösa aviseringar"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Öppna aviseringsinställningarna"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Aviseringar har pausats via Stör ej"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Inga aviseringar}=1{Aviseringar har pausats av {mode}}=2{Aviseringar har pausats av {mode} och ett annat läge}other{Aviseringar har pausats av {mode} och # andra lägen}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string> @@ -755,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, anslutning tillgänglig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-larm via satellit"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Nödsamtal eller 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">"ingen signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"en stapel"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"två staplar"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tre staplar"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"fyra staplar"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"full signalstyrka"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Jobbprofil"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Kul för vissa, inte för alla"</string> <string name="tuner_warning" msgid="1861736288458481650">"Du kan använda inställningarna för systemgränssnitt för att justera användargränssnittet i Android. Dessa experimentfunktioner kan när som helst ändras, sluta fungera eller försvinna. Använd med försiktighet."</string> @@ -788,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Ge feedback om paket"</string> <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> @@ -874,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skärmen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Anteckna"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multikörning"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Använd delad skärm med appen till höger"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Använd delad skärm med appen till vänster"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Byt till helskärm"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Byt till appen till höger eller nedanför när du använder delad skärm"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Byt till appen till vänster eller ovanför när du använder delad skärm"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Med delad skärm: ersätt en app med en annan"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Startmeny"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Låsskärm"</string> - <string name="finder_active" msgid="7907846989716941952">"Du kan hitta den här telefonen med Hitta min enhet även när den är avstängd"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Avslutar …"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Visa alla skötselråd"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Återvänd till startsidan"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se de senaste apparna"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klar"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Svep åt vänster eller höger med tre fingrar på styrplattan"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Bra!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Du är klar med rörelsen för att gå tillbaka."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Återvänd till startskärmen"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Svep uppåt med tre fingrar på styrplattan"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Bra jobbat!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Du är klar med rörelsen för att öppna startskärmen"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Se de senaste apparna"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Svep uppåt med tre fingrar på styrplattan och håll kvar"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbat!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du är klar med rörelsen för att se de senaste apparna."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra gjort!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du är klar med rörelsen för att se alla apparna."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation för guiden: Klicka för att pausa och återuppta uppspelningen."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index cd2c448716ff..a17d6453e51e 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Kitufe cha “Onyesha taswira ya skrini”"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Setilaiti, muunganisho unapatikana"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Msaada kupitia Setilaiti"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Simu za dharura"</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">"hakuna mtandao"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"upau mmoja"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"pau mbili"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"pau tatu"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"pau nne"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"mtandao ni thabiti kabisa"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Wasifu wa kazini"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Kinafurahisha kwa baadhi ya watu lakini si wote"</string> <string name="tuner_warning" msgid="1861736288458481650">"Kirekebishi cha kiolesura cha mfumo kinakupa njia zaidi za kugeuza na kubadilisha kiolesura cha Android ili kikufae. Vipengele hivi vya majaribio vinaweza kubadilika, kuharibika au kupotea katika matoleo ya siku zijazo. Endelea kwa uangalifu."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Toa Maoni kuhusu Kifurushi"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Funga skrini"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Andika dokezo"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Majukumu mengi"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kulia"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kushoto"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Badilisha utumie skrini nzima"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Badilisha ili uende kwenye programu iliyo kulia au chini unapotumia hali ya kugawa skrini"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Badilisha uende kwenye programu iliyo kushoto au juu unapotumia hali ya kugawa skrini"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ukigawanya skrini: badilisha kutoka programu moja hadi nyingine"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyu ya kuzima/kuwasha"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Skrini iliyofungwa"</string> - <string name="finder_active" msgid="7907846989716941952">"Unaweza kutambua mahali ilipo simu hii ukitumia programu ya Tafuta Kifaa Changu hata kama simu hiyo imezimwa"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Inazima…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Angalia hatua za utunzaji"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Nenda kwenye ukurasa wa mwanzo"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Angalia programu za hivi majuzi"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Nimemaliza"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Telezesha vidole vitatu kushoto au kulia kwenye padi yako ya kugusa"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Safi!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Umekamilisha mafunzo ya miguso ya kurudi nyuma."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Nenda kwenye skrini ya kwanza"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Telezesha vidole vitatu juu kwenye padi yako ya kugusa"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Kazi nzuri!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Umeweka ishara ya kwenda kwenye skrini ya kwanza"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Angalia programu za hivi majuzi"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Telezesha vidole vitatu juu kisha ushikilie kwenye padi yako ya kugusa"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kazi nzuri!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Umekamilisha mafunzo ya mguso wa kuangalia programu za hivi majuzi."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vizuri sana!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Umekamilisha mafunzo ya mguso wa kuangalia programu zote"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Uhuishaji wa mafunzo, bofya ili usitishe na uendelee kucheza."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index b4383156dc71..ec24c3df36a8 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -19,10 +19,13 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> -<resources> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">4</integer> + <!-- The number of columns in the Split Shade QuickSettings --> + <integer name="quick_settings_split_shade_num_columns">6</integer> + <!-- Use collapsed layout for media player in landscape QQS --> <bool name="config_quickSettingsMediaLandscapeCollapsed">false</bool> @@ -51,7 +54,9 @@ ignored. --> <string-array name="config_keyguardQuickAffordanceDefaults" translatable="false"> <item>bottom_start:home</item> - <item>bottom_end:create_note</item> + <!-- TODO(b/384119565): revisit decision on defaults --> + <item android:featureFlag="!com.android.systemui.glanceable_hub_v2_resources">bottom_end:create_note</item> + <item android:featureFlag="com.android.systemui.glanceable_hub_v2_resources">bottom_end:glanceable_hub</item> </string-array> <!-- Whether volume panel should use the large screen layout or not --> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index ce630bbc1f1a..3270e5efbf83 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ஸ்கிரீன் சேவரைக் காட்டும் பட்டன்"</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> @@ -754,6 +753,13 @@ <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="828510231597991206">"அவசர அழைப்புகள் அல்லது 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">"ஒரு கோடு"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"இரண்டு கோடுகள்"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"மூன்று கோடுகள்"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"நான்கு கோடுகள்"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"சிக்னல் முழுமையாக உள்ளது"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"பணிக் கணக்கு"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"சில வேடிக்கையாக இருந்தாலும் கவனம் தேவை"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner, Android பயனர் இடைமுகத்தை மாற்றவும் தனிப்பயனாக்கவும் கூடுதல் வழிகளை வழங்குகிறது. இந்தப் பரிசோதனைக்குரிய அம்சங்கள் எதிர்கால வெளியீடுகளில் மாற்றப்படலாம், இடைநிறுத்தப்படலாம் அல்லது தோன்றாமல் போகலாம். கவனத்துடன் தொடரவும்."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"மொத்தமாகக் கருத்தை வழங்கு"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ஆப்ஸ் வலதுபுறம் வரும்படி திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ஆப்ஸ் இடதுபுறம் வரும்படி திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"முழுத்திரைக்கு மாற்றுதல்"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது வலது/கீழ் உள்ள ஆப்ஸுக்கு மாறுதல்"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது இடது/மேலே உள்ள ஆப்ஸுக்கு மாறுதல்"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"திரைப் பிரிப்பின்போது: ஓர் ஆப்ஸுக்குப் பதிலாக மற்றொன்றை மாற்றுதல்"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"பவர் மெனு"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string> - <string name="finder_active" msgid="7907846989716941952">"மொபைல் பவர் ஆஃப் செய்யப்பட்டிருக்கும்போதும் Find My Device மூலம் அதன் இருப்பிடத்தைக் கண்டறியலாம்"</string> <string name="shutdown_progress" msgid="5464239146561542178">"ஷட் டவுன் ஆகிறது…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"முகப்பிற்குச் செல்"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"சமீபத்திய ஆப்ஸைக் காட்டுதல்"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"முடிந்தது"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"பின்செல்"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"உங்கள் டச்பேடில் மூன்று விரல்களால் இடது அல்லது வலதுபுறம் ஸ்வைப் செய்யவும்"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"அருமை!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"பின்செல்வதற்கான சைகையை நிறைவுசெய்துவிட்டீர்கள்."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"முகப்பிற்குச் செல்"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்யவும்"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"அருமை!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"முகப்புக்குச் செல்வதற்கான சைகைப் பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"சமீபத்திய ஆப்ஸைக் காட்டுதல்"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"உங்கள் டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும்"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"அருமை!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"சமீபத்தில் பயன்படுத்திய ஆப்ஸுக்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"அனைத்து ஆப்ஸையும் பார்ப்பதற்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"நிலை, %2$d இல் %1$d"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 20d4cf766d58..ea02e4f6439c 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"శాటిలైట్, కనెక్షన్ అందుబాటులో ఉంది"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ఎమర్జెన్సీ శాటిలైట్ సహాయం"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"ఎమర్జెన్సీ కాల్స్ లేదా 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">"సిగ్నల్ ఒక బార్ ఉంది"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"సిగ్నల్ రెండు బార్లు ఉన్నాయి"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"సిగ్నల్ మూడు బార్లు ఉన్నాయి"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"సిగ్నల్ నాలుగు బార్లు ఉన్నాయి"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"సిగ్నల్ పూర్తిగా ఉంది"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"ఆఫీస్ ప్రొఫైల్"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"కొందరికి సరదాగా ఉంటుంది కానీ అందరికీ అలాగే ఉండదు"</string> <string name="tuner_warning" msgid="1861736288458481650">"సిస్టమ్ UI ట్యూనర్ Android వినియోగదారు ఇంటర్ఫేస్ను మెరుగుపరచడానికి మరియు అనుకూలంగా మార్చడానికి మీకు మరిన్ని మార్గాలను అందిస్తుంది. ఈ ప్రయోగాత్మక లక్షణాలు భవిష్యత్తు విడుదలల్లో మార్పుకు లోనవ్వచ్చు, తాత్కాలికంగా లేదా పూర్తిగా నిలిపివేయవచ్చు. జాగ్రత్తగా కొనసాగండి."</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"బండిల్ ఫీడ్బ్యాక్ను అందించండి"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"కుడి వైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ఎడమ వైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"ఫుల్ స్క్రీన్కు మారండి"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు కుడి లేదా కింద యాప్నకు మారండి"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు ఎడమ లేదా పైన యాప్నకు మారండి"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"స్ప్లిట్ స్క్రీన్ సమయంలో: ఒక దాన్నుండి మరో దానికి యాప్ రీప్లేస్ చేయండి"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"పవర్ మెనూ"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string> - <string name="finder_active" msgid="7907846989716941952">"పవర్ ఆఫ్లో ఉన్నప్పుడు కూడా మీరు Find My Deviceతో ఈ ఫోన్ను గుర్తించవచ్చు"</string> <string name="shutdown_progress" msgid="5464239146561542178">"షట్ డౌన్ చేయబడుతోంది…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string> @@ -1461,27 +1463,37 @@ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"మీ టచ్ప్యాడ్ను ఉపయోగించి నావిగేట్ చేయండి"</string> <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"టచ్ప్యాడ్ సంజ్ఞల గురించి తెలుసుకోండి"</string> <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"మీ కీబోర్డ్, టచ్ప్యాడ్ను ఉపయోగించి నావిగేట్ చేయండి"</string> - <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్కట్లు, అలాగే మరిన్నింటిని గురించి తెలుసుకోండి"</string> + <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్కట్లు మొదలైన వాటి గురించి తెలుసుకోండి"</string> <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> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"మీ టచ్ప్యాడ్లో మూడు వేళ్లను ఉపయోగించి ఎడమ వైపునకు లేదా కుడి వైపునకు స్వైప్ చేయండి"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"సూపర్!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"తిరిగి వెనుకకు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"మొదటి ట్యాబ్కు వెళ్లండి"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"మీ టచ్ప్యాడ్పై మూడు వేళ్లతో పైకి స్వైప్ చేయండి"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"చక్కగా పూర్తి చేశారు!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"మీరు మొదటి స్క్రీన్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ఇటీవలి యాప్లను చూడండి"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"మీ టచ్ప్యాడ్లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"చక్కగా పూర్తి చేశారు!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ఇటీవలి యాప్లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"అన్ని యాప్లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$dలో %1$dవ స్థాయి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index d438e4457778..f8c432770e2d 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"การโทรฉุกเฉินหรือ 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> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 ขีด"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 ขีด"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 ขีด"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"สัญญาณเต็ม"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"โปรไฟล์งาน"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"เพลิดเพลินกับบางส่วนแต่ไม่ใช่ทั้งหมด"</string> <string name="tuner_warning" msgid="1861736288458481650">"ตัวรับสัญญาณ UI ระบบช่วยให้คุณมีวิธีพิเศษในการปรับแต่งและกำหนดค่าส่วนติดต่อผู้ใช้ Android ฟีเจอร์รุ่นทดลองเหล่านี้อาจมีการเปลี่ยนแปลง ขัดข้อง หรือหายไปในเวอร์ชันอนาคต โปรดดำเนินการด้วยความระมัดระวัง"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"แสดงความคิดเห็นเกี่ยวกับแพ็กเกจ"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"ใช้โหมดแยกหน้าจอโดยให้แอปอยู่ด้านขวา"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"ใช้โหมดแยกหน้าจอโดยให้แอปอยู่ด้านซ้าย"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"เปลี่ยนเป็นแบบเต็มหน้าจอ"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"เปลี่ยนไปใช้แอปทางด้านขวาหรือด้านล่างขณะใช้โหมดแยกหน้าจอ"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"เปลี่ยนไปใช้แอปทางด้านซ้ายหรือด้านบนขณะใช้โหมดแยกหน้าจอ"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"ระหว่างใช้โหมดแยกหน้าจอ: เปลี่ยนแอปหนึ่งเป็นอีกแอปหนึ่ง"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"เมนูเปิด/ปิด"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"หน้าจอล็อก"</string> - <string name="finder_active" msgid="7907846989716941952">"คุณจะหาตำแหน่งของโทรศัพท์นี้ได้ด้วยแอปหาอุปกรณ์ของฉันแม้จะปิดเครื่องอยู่ก็ตาม"</string> <string name="shutdown_progress" msgid="5464239146561542178">"กำลังปิด…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ดูขั้นตอนในการดูแลรักษา"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ไปที่หน้าแรก"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ดูแอปล่าสุด"</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> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวาบนทัชแพด"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"ดีมาก"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับสำเร็จแล้ว"</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"หากต้องการย้อนกลับโดยใช้ทัชแพด ให้ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวา"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ไปที่หน้าแรก"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"ใช้ 3 นิ้วปัดขึ้นบนทัชแพด"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"เก่งมาก"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกสำเร็จแล้ว"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"ใช้ 3 นิ้วปัดขึ้นบนทัชแพดเพื่อไปยังหน้าจอหลัก"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"ดูแอปล่าสุด"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string> <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">"หากต้องการดูแอปล่าสุด ให้ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"คุณทำท่าทางสัมผัสเพื่อดูแอปทั้งหมดสำเร็จแล้ว"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"กดปุ่มดำเนินการบนแป้นพิมพ์เพื่อดูแอปทั้งหมด"</string> <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> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index ee152600a3e5..c47da3289a82 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, may koneksyon"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Mga emergency na tawag o 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">"walang signal"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"isang bar"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"dalawang bar"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"tatlong bar"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"apat na bar"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"puno ang signal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profile sa trabaho"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Masaya para sa ilan ngunit hindi para sa lahat"</string> <string name="tuner_warning" msgid="1861736288458481650">"Nagbibigay sa iyo ang Tuner ng System UI ng mga karagdagang paraan upang baguhin at i-customize ang user interface ng Android. Ang mga pang-eksperimentong feature na ito ay maaaring magbago, masira o mawala sa mga pagpapalabas sa hinaharap. Magpatuloy nang may pag-iingat."</string> @@ -786,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Magbigay ng Feedback sa Bundle"</string> <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> @@ -872,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"I-lock ang screen"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Magtala"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Pag-multitask"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Gumamit ng split screen nang nasa kanan ang app"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Gumamit ng split screen nang nasa kaliwa ang app"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Lumipat sa full screen"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Lumipat sa app sa kanan o ibaba habang ginagamit ang split screen"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Lumipat sa app sa kaliwa o itaas habang ginagamit ang split screen"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Habang nasa split screen: magpalit-palit ng app"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string> - <string name="finder_active" msgid="7907846989716941952">"Puwede mong hanapin ang teleponong ito gamit ang Hanapin ang Aking Device kahit kapag naka-off ito"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Nagsa-shut down…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Tingnan ang mga hakbang sa pangangalaga"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string> @@ -1466,22 +1468,27 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pumunta sa home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Tingnan ang mga kamakailang app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tapos na"</string> + <string name="gesture_error_title" msgid="469064941635578511">"Subukan ulit!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Mag-swipe pakaliwa o pakanan gamit ang tatlong daliri sa iyong touchpad"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Magaling!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Nakumpleto mo na ang galaw para bumalik."</string> + <string name="touchpad_back_gesture_error_body" msgid="7112668207481458792">"Para bumalik gamit ang iyong touchpad, mag-swipe pakaliwa o pakanan gamit ang tatlong daliri"</string> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Pumunta sa home"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Mag-swipe pataas gamit ang tatlong daliri sa iyong touchpad"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Magaling!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Nakumpleto mo na ang galaw para pumunta sa home"</string> + <string name="touchpad_home_gesture_error_body" msgid="3810674109999513073">"Mag-swipe pataas gamit ang tatlong daliri sa iyong touchpad para pumunta sa home screen mo"</string> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Tingnan ang mga kamakailang app"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Magaling!"</string> <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="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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Nakumpleto mo ang galaw sa pag-view ng lahat ng app"</string> + <string name="touchpad_action_key_error_body" msgid="8685502040091860903">"Pindutin ang action key sa iyong keyboard para tingnan ang lahat ng app mo"</string> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animation ng tutorial, i-click para i-pause at ipagpatuloy ang paglalaro."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index c12f7b6ea7d7..2a3c44268922 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran koruyucuyu göster düğmesi"</string> <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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirimler"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sessiz bildirimlerin tümünü temizle"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Bildirim ayarlarını aç"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirimler, Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildirim yok}=1{Bildirimler {mode} tarafından duraklatıldı}=2{Bildirimler, {mode} ve bir diğer mod tarafından duraklatıldı}other{Bildirimler, {mode} ve # diğer mod tarafından duraklatıldı}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Şimdi başlat"</string> @@ -755,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Uydu, bağlantı mevcut"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Acil Uydu Bağlantısı"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Acil durum aramaları veya acil yardım"</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">"sinyal yok"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"tek çubuk"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">",ki çubuk"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"üç çubuk"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"dört çubuk"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"tam sinyal"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"İş profili"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Bazıları için eğlenceliyken diğerleri için olmayabilir"</string> <string name="tuner_warning" msgid="1861736288458481650">"Sistem Kullanıcı Arayüzü Ayarlayıcı, Android kullanıcı arayüzünde değişiklikler yapmanız ve arayüzü özelleştirmeniz için ekstra yollar sağlar. Bu deneysel özellikler değişebilir, bozulabilir veya gelecekteki sürümlerde yer almayabilir. Dikkatli bir şekilde devam edin."</string> @@ -788,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Paketle İlgili Geri Bildirim Verin"</string> <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> @@ -874,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Kilit ekranı"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Not al"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Çoklu görev"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Sağdaki uygulamayla birlikte bölünmüş ekranı kullan"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Soldaki uygulamayla birlikte bölünmüş ekranı kullan"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Tam ekran moduna geç"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran kullanırken sağdaki veya alttaki uygulamaya geçiş yap"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran kullanırken soldaki veya üstteki uygulamaya geçiş yapın"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Bölünmüş ekran etkinken: Bir uygulamayı başkasıyla değiştir"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Güç menüsü"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Kilit ekranı"</string> - <string name="finder_active" msgid="7907846989716941952">"Bu telefonu kapalıyken bile Cihazımı Bul işleviyle bulabilirsiniz."</string> <string name="shutdown_progress" msgid="5464239146561542178">"Kapanıyor…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bakımla ilgili adımlara bakın"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ana sayfaya git"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son uygulamaları görüntüle"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Bitti"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Dokunmatik alanda üç parmağınızla sola veya sağa kaydırın"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Güzel!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Geri dön hareketini tamamladınız."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Ana sayfaya gidin"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Dokunmatik alanda üç parmağınızla yukarı kaydırın"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Tebrikler!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ana ekrana git hareketini tamamladınız"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Son uygulamaları görüntüle"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Dokunmatik alanda üç parmağınızla yukarı doğru kaydırıp basılı tutun"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tebrikler!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son uygulamaları görüntüleme hareketini tamamladınız."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Tebrikler!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Tüm uygulamaları görüntüleme hareketini tamamladınız"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Eğitim animasyonu, oynatmayı duraklatmak ve sürdürmek için tıklayın."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index c2c3c61a49c7..68129a84c349 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Показати заставку\""</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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Сповіщення"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Відкрити налаштування сповіщень"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Немає сповіщень}=1{Режим \"{mode}\" призупинив надсилання сповіщень}=2{\"{mode}\" і ще один режим призупинили надсилання сповіщень}one{\"{mode}\" і ще # режим призупинили надсилання сповіщень}few{\"{mode}\" і ще # режими призупинили надсилання сповіщень}many{\"{mode}\" і ще # режимів призупинили надсилання сповіщень}other{\"{mode}\" і ще # режиму призупинили надсилання сповіщень}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string> @@ -755,6 +753,13 @@ <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="828510231597991206">"Екстрені виклики або сигнал 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">"одна смужка сигналу"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"дві смужки сигналу"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"три смужки сигналу"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"чотири смужки сигналу"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"максимальний сигнал"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Робочий профіль"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Це цікаво, але будьте обачні"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner пропонує нові способи налаштувати та персоналізувати інтерфейс користувача Android. Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string> @@ -788,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Надіслати груповий відгук"</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> @@ -874,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Розділити екран і показувати додаток праворуч"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Розділити екран і показувати додаток ліворуч"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Перейти в повноекранний режим"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти до додатка праворуч або внизу на розділеному екрані"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Під час розділення екрана перемикатися на додаток ліворуч або вгорі"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Під час розділення екрана: замінити додаток іншим"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки живлення"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокований екран"</string> - <string name="finder_active" msgid="7907846989716941952">"Ви зможете визначити місцеположення цього телефона, навіть коли його вимкнено, за допомогою сервісу Знайти пристрій"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Вимкнення…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Переглянути запобіжні заходи"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути запобіжні заходи"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Перейти на головний екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Переглянути нещодавні додатки"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Проведіть трьома пальцями вліво чи вправо по сенсорній панелі"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Чудово!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ви виконали жест \"Назад\"."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Перейти на головний екран"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Проведіть трьома пальцями вгору на сенсорній панелі"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Чудово!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ви виконали жест переходу на головний екран"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Переглянути нещодавні додатки"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Проведіть трьома пальцями вгору й утримуйте їх на сенсорній панелі"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Чудово!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ви виконали жест для перегляду нещодавно відкритих додатків."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ви виконали жест для перегляду всіх додатків"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 8b3b9a026fe8..63213da49ebe 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -753,6 +753,13 @@ <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="828510231597991206">"ایمرجنسی کالز یا 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">"ایک بار"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"دو بارز"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"تین بارز"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"چار بارز"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"سگنل فل ہے"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"دفتری پروفائل"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"کچھ کیلئے دلچسپ لیکن سبھی کیلئے نہیں"</string> <string name="tuner_warning" msgid="1861736288458481650">"سسٹم UI ٹیونر Android صارف انٹر فیس میں ردوبدل کرنے اور اسے حسب ضرورت بنانے کیلئے آپ کو اضافی طریقے دیتا ہے۔ یہ تجرباتی خصوصیات مستقبل کی ریلیزز میں تبدیل ہو سکتی، رک سکتی یا غائب ہو سکتی ہیں۔ احتیاط کے ساتھ آگے بڑھیں۔"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"بنڈل کے تاثرات فراہم کریں"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"بائیں جانب ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"دائیں جانب ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"فُل اسکرین پر سوئچ کریں"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"اسپلٹ اسکرین کا استعمال کرتے ہوئے دائیں یا نیچے ایپ پر سوئچ کریں"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"اسپلٹ اسکرین کا استعمال کرتے ہوئے بائیں یا اوپر ایپ پر سوئچ کریں"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"اسپلٹ اسکرین کے دوران: ایک ایپ کو دوسرے سے تبدیل کریں"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"پاور مینیو"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"مقفل اسکرین"</string> - <string name="finder_active" msgid="7907846989716941952">"پاور آف ہونے پر بھی آپ میرا آلہ ڈھونڈیں کے ساتھ اس فون کو تلاش کر سکتے ہیں"</string> <string name="shutdown_progress" msgid="5464239146561542178">"بند ہو رہا ہے…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"نگہداشت کے اقدامات ملاحظہ کریں"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"نگہداشت کے اقدامات ملاحظہ کریں"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ہوم پر جائیں"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"حالیہ ایپس دیکھیں"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ہو گیا"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے دائیں یا بائیں طرف سوائپ کریں"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"عمدہ!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"آپ نے واپس جائیں اشارے کو مکمل کر لیا۔"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"ہوم پر جائیں"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"اپنے ٹچ پیڈ پر تین انگلیوں کی مدد سے اوپر کی طرف سوائپ کریں"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"بہترین!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"حالیہ ایپس دیکھیں"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"اپنے ٹچ پیڈ پر تین انگلیوں کا استعمال کرتے ہوئے اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"بہترین!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"آپ نے حالیہ ایپس دیکھیں کا اشارہ مکمل کر لیا ہے۔"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"آپ نے سبھی ایپس دیکھیں کا اشارہ مکمل کر لیا ہے"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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">"%2$d میں سے %1$d کا لیول"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index dc01a492356d..488852f525d2 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran lavhasi tugmasini chiqarish"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sputnik, aloqa mavjud"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Sputnik SOS"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Favqulodda chaqiruvlar yoki 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">"signal yoʻq"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"bitta ustun"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"ikkita ustun"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"uchta ustun"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"toʻrtta ustun"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"signal toʻliq"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Ish profili"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Diqqat!"</string> <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner yordamida siz Android foydalanuvchi interfeysini tuzatish va o‘zingizga moslashtirishingiz mumkin. Ushbu tajribaviy funksiyalar o‘zgarishi, buzilishi yoki keyingi versiyalarda olib tashlanishi mumkin. Ehtiyot bo‘lib davom eting."</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"Jamlanma fikr-mulohaza bildirish"</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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Ekran qulfi"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Qayd yaratish"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-vazifalilik"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Ekranni ajratib, joriy ilovani oʻngga joylash"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Ekranni ajratib, joriy ilovani chapga joylash"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Butun ekran rejimiga kirish"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ajratilgan ekranda oʻngdagi yoki pastdagi ilovaga almashish"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ajratilgan ekranda chapdagi yoki yuqoridagi ilovaga almashish"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ajratilgan rejimda ilovalarni oʻzaro almashtirish"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Quvvat menyusi"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran qulfi"</string> - <string name="finder_active" msgid="7907846989716941952">"Oʻchiq boʻlsa ham “Qurilmani top” funksiyasi yordamida bu telefonni topish mumkin"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Oʻchirilmoqda…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Batafsil axborot"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Boshiga qaytish"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Oxirgi ilovalarni koʻrish"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tayyor"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Sensorli panelda uchta barmoq bilan chapga yoki oʻngga suring"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Yaxshi!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ortga qaytish ishorasi darsini tamomladingiz."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Boshiga qaytish"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Sensorli panelda uchta barmoq bilan tepaga suring"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Barakalla!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Bosh ekranni ochish ishorasi darsini tamomladingiz"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Oxirgi ilovalarni koʻrish"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Sensorli panelda uchta barmoq bilan tepaga surib, bosib turing"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Barakalla!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Oxirgi ilovalarni koʻrish ishorasini tugalladingiz."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Hamma ilovalarni koʻrish ishorasini tugalladingiz"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Qoʻllanma animatsiyasi, pauza qilish va ijroni davom ettirish uchun bosing."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 1dd604273d00..1b505d3d4426 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Hiện nút trình bảo vệ màn hình"</string> <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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Hiện có kết nối vệ tinh"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Liên lạc khẩn cấp qua vệ tinh"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Cuộc gọi khẩn cấp hoặc 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">"không có tín hiệu"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"1 vạch"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"2 vạch"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"3 vạch"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"4 vạch"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"tín hiệu đầy đủ"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Hồ sơ công việc"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Thú vị đối với một số người nhưng không phải tất cả"</string> <string name="tuner_warning" msgid="1861736288458481650">"Bộ điều hướng giao diện người dùng hệ thống cung cấp thêm cho bạn những cách chỉnh sửa và tùy chỉnh giao diện người dùng Android. Những tính năng thử nghiệm này có thể thay đổi, hỏng hoặc biến mất trong các phiên bản tương lai. Hãy thận trọng khi tiếp tục."</string> @@ -787,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Phản hồi về gói"</string> <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> @@ -873,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Màn hình khoá"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Tạo ghi chú"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Đa nhiệm"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Dùng tính năng chia đôi màn hình với ứng dụng ở bên phải"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Dùng tính năng chia đôi màn hình với ứng dụng ở bên trái"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Chuyển sang chế độ toàn màn hình"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Chuyển sang ứng dụng bên phải hoặc ở dưới khi đang chia đôi màn hình"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Chuyển sang ứng dụng bên trái hoặc ở trên khi đang chia đôi màn hình"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Trong chế độ chia đôi màn hình: thay một ứng dụng bằng ứng dụng khác"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Trình đơn nguồn"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Màn hình khóa"</string> - <string name="finder_active" msgid="7907846989716941952">"Bạn có thể định vị chiếc điện thoại này bằng ứng dụng Tìm thiết bị của tôi ngay cả khi điện thoại tắt nguồn"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Đang tắt…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Xem các bước chăm sóc"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Chuyển đến màn hình chính"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Xem các ứng dụng gần đây"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Xong"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Dùng 3 ngón tay vuốt sang trái hoặc sang phải trên bàn di chuột"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Tuyệt vời!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Bạn đã thực hiện xong cử chỉ quay lại."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Chuyển đến màn hình chính"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Dùng 3 ngón tay vuốt lên trên bàn di chuột"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Tuyệt vời!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Bạn đã thực hiện xong cử chỉ chuyển đến màn hình chính"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Xem các ứng dụng gần đây"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tuyệt vời!"</string> <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> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Rất tốt!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Bạn đã hoàn tất cử chỉ xem tất cả các ứng dụng"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Ảnh động trong phần hướng dẫn, nhấp để tạm dừng và tiếp tục phát."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index e18fcec9f897..8d6ec77ae5a8 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"卫星,可连接"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"卫星紧急呼救"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"紧急呼叫或紧急求救"</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">"信号强度为一格"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"信号强度为两格"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"信号强度为三格"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"信号强度为四格"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"信号满格"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"工作资料"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"并不适合所有用户"</string> <string name="tuner_warning" msgid="1861736288458481650">"系统界面调节工具可让您以更多方式调整及定制 Android 界面。在日后推出的版本中,这些实验性功能可能会变更、失效或消失。操作时请务必谨慎。"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"提供有关套装的反馈"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分屏模式,并将应用置于右侧"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分屏模式,并将应用置于左侧"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"切换到全屏模式"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分屏模式时,切换到右侧或下方的应用"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分屏模式时,切换到左侧或上方的应用"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"在分屏期间:将一个应用替换为另一个应用"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"电源菜单"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"锁定屏幕"</string> - <string name="finder_active" msgid="7907846989716941952">"即使手机已关机,您也可以通过“查找我的设备”找到这部手机"</string> <string name="shutdown_progress" msgid="5464239146561542178">"正在关机…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看处理步骤"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"前往主屏幕"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近用过的应用"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在触控板上用三根手指向左或向右滑动"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"太棒了!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"您已完成“返回”手势教程。"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"前往主屏幕"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在触控板上用三根手指向上滑动"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太棒了!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"您已完成“前往主屏幕”手势"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近用过的应用"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在触控板上用三根手指向上滑动并按住"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"您已完成“查看最近用过的应用”的手势教程。"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"您已完成“查看所有应用”手势教程"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 871bd31bbbd3..b1df372dd26b 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -753,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可以連線"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連接"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"緊急電話或 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">"一格"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"兩格"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"三格"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"四格"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"訊號滿格"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"工作設定檔"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"這只是測試版本,並不包含完整功能"</string> <string name="tuner_warning" msgid="1861736288458481650">"使用者介面調諧器讓你以更多方法修改和自訂 Android 使用者介面。但請小心,這些實驗功能可能會在日後發佈時更改、分拆或消失。"</string> @@ -786,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"提供套裝意見"</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> @@ -872,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分割螢幕,並在右側顯示應用程式"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分割螢幕,並在左側顯示應用程式"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"切換至全螢幕"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割螢幕時,切換至右邊或下方的應用程式"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割螢幕時,切換至左邊或上方的應用程式"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割螢幕期間:更換應用程式"</string> @@ -979,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源選單"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string> - <string name="finder_active" msgid="7907846989716941952">"即使手機關機,仍可透過「尋找我的裝置」尋找此手機"</string> <string name="shutdown_progress" msgid="5464239146561542178">"正在關機…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看保養步驟"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string> @@ -1466,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在觸控板上用三隻手指向左或向右滑動"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"很好!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"你已完成「返回」手勢的教學課程。"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"返回主畫面"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在觸控板上用三隻手指向上滑動"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太好了!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"你已完成「返回主畫面」手勢的教學課程"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近使用的應用程式"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在觸控板上用三隻手指向上滑動並按住"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"做得好!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢的教學課程。"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢的教學課程"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 334117540509..373f1af06c13 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"顯示螢幕保護程式按鈕"</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> @@ -754,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可連線"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連線"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"緊急電話或緊急求救"</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">"訊號強度一格"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"訊號強度兩格"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"訊號強度三格"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"訊號強度四格"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"訊號滿格"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"工作資料夾"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"有趣與否,見仁見智"</string> <string name="tuner_warning" msgid="1861736288458481650">"系統使用者介面調整精靈可讓你透過其他方式,調整及自訂 Android 使用者介面。這些實驗性功能隨著版本更新可能會變更、損壞或消失,執行時請務必謹慎。"</string> @@ -787,7 +793,6 @@ <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_guts_bundle_feedback" msgid="5393570876655201459">"提供套裝組合意見"</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> @@ -873,12 +878,9 @@ <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> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"使用分割畫面,並在右側顯示應用程式"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"使用分割畫面,並在左側顯示應用程式"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"切換至全螢幕模式"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割畫面時,切換到右邊或上方的應用程式"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割畫面時,切換到左邊或上方的應用程式"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"使用分割畫面期間:更換應用程式"</string> @@ -980,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源鍵選單"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string> - <string name="finder_active" msgid="7907846989716941952">"即使這支手機關機,仍可透過「尋找我的裝置」找出手機位置"</string> <string name="shutdown_progress" msgid="5464239146561542178">"關機中…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看處理步驟"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string> @@ -1467,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"在觸控板上用三指向左或向右滑動"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"很好!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"你已完成「返回」手勢的教學課程。"</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"返回主畫面"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"在觸控板上用三指向上滑動"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"太棒了!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"你已完成「返回主畫面」手勢教學課程"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"查看最近使用的應用程式"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"在觸控板上用三指向上滑動並按住"</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢教學課程。"</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <skip /> <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> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢教學課程"</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index a9fa1ba36df2..a18d9e7e02c2 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -531,8 +531,7 @@ <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> - <!-- no translation found for accessibility_glanceable_hub_to_dream_button (7552776300297055307) --> - <skip /> + <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Bonisa inkinobho yesigcini sesikrini"</string> <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> @@ -593,8 +592,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Izaziso"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sula zonke izaziso ezithulile"</string> - <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> - <skip /> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Vula amasethingi ezaziso"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Izaziso zimiswe okwesikhashana ukungaphazamisi"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Azikho izaziso}=1{Izaziso zimiswe okwesikhashana yi-{mode}}=2{Izaziso zimiswe okwesikhashana yi-{mode} nelinye imodi elilodwa}one{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}other{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Qala manje"</string> @@ -755,6 +753,13 @@ <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Isethelayithi, uxhumano luyatholakala"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Isethelayithi yokuxhumana ngezimo eziphuthumayo"</string> <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"Ikholi ephuthumayo noma i-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">"ayikho isignali"</string> + <string name="accessibility_one_bar" msgid="5342012847647834506">"ibha eyodwa"</string> + <string name="accessibility_two_bars" msgid="122628483354508429">"amabha amabili"</string> + <string name="accessibility_three_bars" msgid="5143286602926069024">"amabha amathathu"</string> + <string name="accessibility_four_bars" msgid="8838495563822541844">"amabha amane"</string> + <string name="accessibility_signal_full" msgid="1519655809806462972">"isignali egcwele"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Iphrofayela yomsebenzi"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Kuyajabulisa kwabanye kodwa hhayi bonke"</string> <string name="tuner_warning" msgid="1861736288458481650">"Isishuni se-UI sesistimu sikunika izindlela ezingeziwe zokuhlobisa nokwenza ngezifiso isixhumanisi sokubona se-Android. Lezi zici zesilingo zingashintsha, zephuke, noma zinyamalale ekukhishweni kwangakusasa. Qhubeka ngokuqaphela."</string> @@ -788,7 +793,6 @@ <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> - <string name="notification_guts_bundle_feedback" msgid="5393570876655201459">"Nikeza Impendulo Yenqwaba"</string> <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> @@ -874,12 +878,9 @@ <string name="group_system_lock_screen" msgid="7391191300363416543">"Khiya isikrini"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Thatha inothi"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Ukwenza imisebenzi eminingi"</string> - <!-- no translation found for system_multitasking_rhs (8779289852395243004) --> - <skip /> - <!-- no translation found for system_multitasking_lhs (7348595296208696452) --> - <skip /> - <!-- no translation found for system_multitasking_full_screen (4940465971687159429) --> - <skip /> + <string name="system_multitasking_rhs" msgid="8779289852395243004">"Sebenzisa ukuhlukanisa isikrini nge-app kwesokudla"</string> + <string name="system_multitasking_lhs" msgid="7348595296208696452">"Sebenzisa ukuhlukanisa isikrini nge-app kwesokunxele"</string> + <string name="system_multitasking_full_screen" msgid="4940465971687159429">"Shintshela esikrinini esigcwele"</string> <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Shintshela ku-app ngakwesokudla noma ngezansi ngenkathi usebenzisa uhlukanisa isikrini"</string> <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Shintshela ku-app ngakwesokunxele noma ngaphezulu ngenkathi usebenzisa ukuhlukanisa isikrini"</string> <string name="system_multitasking_replace" msgid="7410071959803642125">"Ngesikhathi sokuhlukaniswa kwesikrini: shintsha i-app ngenye"</string> @@ -981,7 +982,6 @@ <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Imenyu yamandla"</string> <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="tuner_lock_screen" msgid="2267383813241144544">"Khiya isikrini"</string> - <string name="finder_active" msgid="7907846989716941952">"Ungabeka le foni ngokuthi Thola Ifoni Yami ngisho noma ivaliwe"</string> <string name="shutdown_progress" msgid="5464239146561542178">"Iyacisha…"</string> <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bona izinyathelo zokunakekelwa"</string> <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string> @@ -1468,22 +1468,32 @@ <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Iya ekhasini lokuqala"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Buka ama-app akamuva"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kwenziwe"</string> + <!-- no translation found for gesture_error_title (469064941635578511) --> + <skip /> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string> <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"Swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu kuphedi yokuthinta"</string> <string name="touchpad_back_gesture_success_title" msgid="7370719098633023496">"Kuhle!"</string> <string name="touchpad_back_gesture_success_body" msgid="2324724953720741719">"Ukuqedile ukuthinta kokubuyela emuva."</string> + <!-- no translation found for touchpad_back_gesture_error_body (7112668207481458792) --> + <skip /> <string name="touchpad_home_gesture_action_title" msgid="8885107349719257882">"Iya ekhasini lokuqala"</string> <string name="touchpad_home_gesture_guidance" msgid="4178219118381915899">"Swayiphela phezulu ngeminwe emithathu ephedini yakho yokuthinta"</string> <string name="touchpad_home_gesture_success_title" msgid="3648264553645798470">"Umsebenzi omuhle!"</string> <string name="touchpad_home_gesture_success_body" msgid="2590690589194027059">"Ukuqedile ukunyakaza kokuya ekhaya"</string> + <!-- no translation found for touchpad_home_gesture_error_body (3810674109999513073) --> + <skip /> <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"Buka ama-app akamuva"</string> <string name="touchpad_recent_apps_gesture_guidance" msgid="6304446013842271822">"Swayiphela phezulu bese ubamba usebenzisa iminwe emithathu ephedini yokuthinta."</string> <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Umsebenzi omuhle!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Uqedele ukubuka ukuthinta kwama-app akamuva."</string> + <!-- no translation found for touchpad_recent_gesture_error_body (8695535720378462022) --> + <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> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Wenze kahle!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Uqedele ukunyakazisa kokubuka onke ama-app."</string> + <!-- no translation found for touchpad_action_key_error_body (8685502040091860903) --> + <skip /> <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Okopopayi okokufundisa, chofoza ukuze umise kancane futhi uqalise kabusha ukudlala."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 28df2e2a1b8c..d2b7d0b90c43 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -31,6 +31,9 @@ <!-- The dark background color behind the shade --> <color name="shade_scrim_background_dark">@androidprv:color/system_under_surface_light</color> + <!-- Colors for notification shade/scrim --> + <color name="shade_panel">@android:color/system_accent1_800</color> + <!-- The color of the background in the separated list of the Global Actions menu --> <color name="global_actions_separated_background">#F5F5F5</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 35cfd082c537..05c4d1b662db 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -2106,6 +2106,8 @@ <fraction name="volume_dialog_half_opened_bias">0.2</fraction> + <dimen name="volume_dialog_slider_max_deviation">56dp</dimen> + <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> <dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 56aaf4c0c564..c3d84ff39485 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1004,6 +1004,20 @@ <string name="hearing_devices_preset_label">Preset</string> <!-- QuickSettings: Content description for the icon that indicates the item is selected [CHAR LIMIT=NONE]--> <string name="hearing_devices_spinner_item_selected">Selected</string> + <!-- QuickSettings: Title for ambient controls. [CHAR LIMIT=40]--> + <string name="hearing_devices_ambient_label">Surroundings</string> + <!-- QuickSettings: The text to show the control is for left side device. [CHAR LIMIT=30] --> + <string name="hearing_devices_ambient_control_left">Left</string> + <!-- QuickSettings: The text to show the control is for right side device. [CHAR LIMIT=30] --> + <string name="hearing_devices_ambient_control_right">Right</string> + <!-- QuickSettings: Content description for a button, that expands ambient volume sliders [CHAR_LIMIT=NONE] --> + <string name="hearing_devices_ambient_expand_controls">Expand to left and right separated controls</string> + <!-- QuickSettings: Content description for a button, that collapses ambient volume sliders [CHAR LIMIT=NONE] --> + <string name="hearing_devices_ambient_collapse_controls">Collapse to unified control</string> + <!-- QuickSettings: Content description for a button, that mute ambient volume [CHAR_LIMIT=NONE] --> + <string name="hearing_devices_ambient_mute">Mute surroundings</string> + <!-- QuickSettings: Content description for a button, that unmute ambient volume [CHAR LIMIT=NONE] --> + <string name="hearing_devices_ambient_unmute">Unmute surroundings</string> <!-- QuickSettings: Title for related tools of hearing. [CHAR LIMIT=40]--> <string name="hearing_devices_tools_label">Tools</string> <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]--> @@ -2504,14 +2518,14 @@ <!-- Accessibility description of action to remove QS tile on click. It will read as "Double-tap to remove tile" in screen readers [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_remove_tile_action">remove tile</string> - <!-- Accessibility action of action to add QS tile to end. It will read as "Double-tap to add tile to end" in screen readers [CHAR LIMIT=NONE] --> - <string name="accessibility_qs_edit_tile_add_action">add tile to end</string> + <!-- Accessibility action of action to add QS tile to end. It will read as "Double-tap to add tile to the last position" in screen readers [CHAR LIMIT=NONE] --> + <string name="accessibility_qs_edit_tile_add_action">add tile to the last position</string> <!-- Accessibility action for context menu to move QS tile [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_start_move">Move tile</string> - <!-- Accessibility action for context menu to add QS tile [CHAR LIMIT=NONE] --> - <string name="accessibility_qs_edit_tile_start_add">Add tile</string> + <!-- Accessibility action for context menu to add QS tile to a position [CHAR LIMIT=NONE] --> + <string name="accessibility_qs_edit_tile_start_add">Add tile to desired position</string> <!-- Accessibility description when QS tile is to be moved, indicating the destination position [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_tile_move_to_position">Move to <xliff:g id="position" example="5">%1$d</xliff:g></string> @@ -2564,7 +2578,7 @@ <string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string> <!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] --> - <string name="accessibility_quick_settings_edit">Edit order of settings.</string> + <string name="accessibility_quick_settings_edit">Edit order of Quick Settings.</string> <!-- accessibility label for button to open power menu [CHAR LIMIT=NONE] --> <string name="accessibility_quick_settings_power_menu">Power menu</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 3156a50df96f..71806781b98e 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -91,7 +91,6 @@ <item name="android:ellipsize">none</item> <item name="android:requiresFadingEdge">horizontal</item> <item name="android:fadingEdgeLength">@dimen/ongoing_activity_chip_text_fading_edge_length</item> - <item name="android:maxWidth">@dimen/ongoing_activity_chip_max_text_width</item> </style> <style name="Chipbar" /> @@ -559,15 +558,18 @@ <style name="SystemUI.Material3.Slider.Volume"> <item name="trackHeight">40dp</item> <item name="thumbHeight">52dp</item> + <item name="trackCornerSize">12dp</item> + <item name="trackInsideCornerSize">2dp</item> + <item name="trackStopIndicatorSize">6dp</item> </style> <style name="SystemUI.Material3.Slider" parent="@style/Widget.Material3.Slider"> <item name="labelStyle">@style/Widget.Material3.Slider.Label</item> - <item name="thumbColor">@color/slider_thumb_color</item> - <item name="tickColorActive">@color/slider_inactive_track_color</item> - <item name="tickColorInactive">@color/slider_active_track_color</item> - <item name="trackColorActive">@color/slider_active_track_color</item> - <item name="trackColorInactive">@color/slider_inactive_track_color</item> + <item name="thumbColor">@androidprv:color/materialColorPrimary</item> + <item name="tickColorActive">@androidprv:color/materialColorSurfaceContainerHighest</item> + <item name="tickColorInactive">@androidprv:color/materialColorPrimary</item> + <item name="trackColorActive">@androidprv:color/materialColorPrimary</item> + <item name="trackColorInactive">@androidprv:color/materialColorSurfaceContainerHighest</item> </style> <style name="Theme.SystemUI.DayNightDialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"/> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java index 82983973b5f5..69f5a79ece2f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java @@ -108,7 +108,8 @@ public class PluginInstance<T extends Plugin> } @Override - public synchronized boolean onFail(String className, String methodName, LinkageError failure) { + public synchronized boolean onFail(String className, String methodName, Throwable failure) { + Log.e(TAG, "Failure from " + mPlugin + ". Disabling Plugin."); mHasError = true; unloadPlugin(); mListener.onPluginDetached(this); @@ -118,7 +119,7 @@ public class PluginInstance<T extends Plugin> /** Alerts listener and plugin that the plugin has been created. */ public synchronized void onCreate() { if (mHasError) { - log("Previous LinkageError detected for plugin class"); + log("Previous Fatal Exception detected for plugin class"); return; } @@ -175,7 +176,7 @@ public class PluginInstance<T extends Plugin> */ public synchronized void loadPlugin() { if (mHasError) { - log("Previous LinkageError detected for plugin class"); + log("Previous Fatal Exception detected for plugin class"); return; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index fc536bdb126b..6f13d637d5c5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -20,6 +20,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static com.android.systemui.Flags.glanceableHubBackAction; import static com.android.systemui.shared.Flags.shadeAllowBackGesture; import android.annotation.LongDef; @@ -352,6 +353,10 @@ public class QuickStepContract { } // Disable back gesture on the hub, but not when the shade is showing. if ((sysuiStateFlags & SYSUI_STATE_COMMUNAL_HUB_SHOWING) != 0) { + // Allow back gesture on Glanceable Hub with back action support. + if (glanceableHubBackAction()) { + return false; + } // Use QS expanded signal as the notification panel is always considered visible // expanded when on the lock screen and when opening hub over lock screen. This does // mean that back gesture is disabled when opening shade over hub while in portrait diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt index f9fe67ac2076..c13bb3e4f60f 100644 --- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt +++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt @@ -67,7 +67,7 @@ object FlagsFactory { namespace: String = "systemui", default: Boolean = false ): SysPropBooleanFlag { - val flag = SysPropBooleanFlag(name = name, namespace = "systemui", default = default) + val flag = SysPropBooleanFlag(name = name, namespace, default = default) checkForDupesAndAdd(flag) return flag } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 5af80cbd4b29..71b622aa0608 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -43,7 +43,6 @@ import com.android.systemui.dagger.qualifiers.DisplaySpecific import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags.REGION_SAMPLING -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -85,8 +84,8 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge /** - * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by - * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController]. + * Controller for a Clock provided by the registry and used on the keyguard. Functionality is forked + * from [AnimatableClockController]. */ open class ClockEventController @Inject @@ -348,14 +347,6 @@ constructor( object : KeyguardUpdateMonitorCallback() { override fun onKeyguardVisibilityChanged(visible: Boolean) { isKeyguardVisible = visible - if (!MigrateClocksToBlueprint.isEnabled) { - if (!isKeyguardVisible) { - clock?.run { - smallClock.animations.doze(if (isDozing) 1f else 0f) - largeClock.animations.doze(if (isDozing) 1f else 0f) - } - } - } if (visible) { refreshTime() @@ -388,10 +379,6 @@ constructor( } private fun refreshTime() { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } - clock?.smallClock?.events?.onTimeTick() clock?.largeClock?.events?.onTimeTick() } @@ -483,14 +470,10 @@ constructor( if (ModesUi.isEnabled) { listenForDnd(this) } - if (MigrateClocksToBlueprint.isEnabled) { - listenForDozeAmountTransition(this) - listenForAnyStateToAodTransition(this) - listenForAnyStateToLockscreenTransition(this) - listenForAnyStateToDozingTransition(this) - } else { - listenForDozeAmount(this) - } + listenForDozeAmountTransition(this) + listenForAnyStateToAodTransition(this) + listenForAnyStateToLockscreenTransition(this) + listenForAnyStateToDozingTransition(this) } } smallTimeListener?.update(shouldTimeListenerRun) @@ -596,11 +579,6 @@ constructor( } @VisibleForTesting - internal fun listenForDozeAmount(scope: CoroutineScope): Job { - return scope.launch { keyguardInteractor.dozeAmount.collect { handleDoze(it) } } - } - - @VisibleForTesting internal fun listenForDozeAmountTransition(scope: CoroutineScope): Job { return scope.launch { merge( @@ -695,8 +673,7 @@ constructor( isRunning = true when (clockFace.config.tickRate) { ClockTickRate.PER_MINUTE -> { - // Handled by KeyguardClockSwitchController and - // by KeyguardUpdateMonitorCallback#onTimeChanged. + // Handled by KeyguardUpdateMonitorCallback#onTimeChanged. } ClockTickRate.PER_SECOND -> executor.execute(secondsRunnable) ClockTickRate.PER_FRAME -> { diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt index df77a58c3b34..3f332f769c6e 100644 --- a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt +++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt @@ -23,14 +23,11 @@ import android.graphics.Rect import android.os.Bundle import android.view.Display import android.view.Gravity -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.WindowManager import android.widget.FrameLayout import android.widget.FrameLayout.LayoutParams -import com.android.keyguard.dagger.KeyguardStatusViewComponent -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.res.R @@ -45,7 +42,6 @@ class ConnectedDisplayKeyguardPresentation constructor( @Assisted display: Display, context: Context, - private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory, private val clockRegistry: ClockRegistry, private val clockEventController: ClockEventController, ) : @@ -53,12 +49,11 @@ constructor( context, display, R.style.Theme_SystemUI_KeyguardPresentation, - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, ) { private lateinit var rootView: FrameLayout private var clock: View? = null - private lateinit var keyguardStatusViewController: KeyguardStatusViewController private lateinit var faceController: ClockFaceController private lateinit var clockFrame: FrameLayout @@ -82,7 +77,7 @@ constructor( oldLeft: Int, oldTop: Int, oldRight: Int, - oldBottom: Int + oldBottom: Int, ) { clock?.let { faceController.events.onTargetRegionChanged( @@ -95,11 +90,7 @@ constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (MigrateClocksToBlueprint.isEnabled) { - onCreateV2() - } else { - onCreate() - } + onCreateV2() } fun onCreateV2() { @@ -112,39 +103,15 @@ constructor( setClock(clockRegistry.createCurrentClock()) } - fun onCreate() { - setContentView( - LayoutInflater.from(context) - .inflate(R.layout.keyguard_clock_presentation, /* root= */ null) - ) - - setFullscreen() - - clock = requireViewById(R.id.clock) - keyguardStatusViewController = - keyguardStatusViewComponentFactory - .build(clock as KeyguardStatusView, display) - .keyguardStatusViewController - .apply { - setDisplayedOnSecondaryDisplay() - init() - } - } - override fun onAttachedToWindow() { - if (MigrateClocksToBlueprint.isEnabled) { - clockRegistry.registerClockChangeListener(clockChangedListener) - clockEventController.registerListeners(clock!!) - - faceController.animations.enter() - } + clockRegistry.registerClockChangeListener(clockChangedListener) + clockEventController.registerListeners(clock!!) + faceController.animations.enter() } override fun onDetachedFromWindow() { - if (MigrateClocksToBlueprint.isEnabled) { - clockEventController.unregisterListeners() - clockRegistry.unregisterClockChangeListener(clockChangedListener) - } + clockEventController.unregisterListeners() + clockRegistry.unregisterClockChangeListener(clockChangedListener) super.onDetachedFromWindow() } @@ -166,7 +133,7 @@ constructor( context.resources.getDimensionPixelSize(R.dimen.keyguard_presentation_width), WRAP_CONTENT, Gravity.CENTER, - ) + ), ) clockEventController.clock = clockController @@ -190,8 +157,6 @@ constructor( @AssistedFactory interface Factory { /** Creates a new [Presentation] for the given [display]. */ - fun create( - display: Display, - ): ConnectedDisplayKeyguardPresentation + fun create(display: Display): ConnectedDisplayKeyguardPresentation } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 1083136b570a..acfa08643b63 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -26,11 +26,9 @@ import android.hardware.display.DisplayManager; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.os.Trace; -import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.view.Display; -import android.view.DisplayAddress; import android.view.DisplayInfo; import android.view.View; import android.view.WindowManager; @@ -58,6 +56,9 @@ import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Provider; +/** + * Manages Keyguard Presentations for non-primary display(s). + */ @SysUISingleton public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; @@ -170,14 +171,17 @@ public class KeyguardDisplayManager { } return false; } - if (mKeyguardStateController.isOccluded() - && mDeviceStateHelper.isConcurrentDisplayActive(display)) { + + final boolean deviceStateOccludesKeyguard = + mDeviceStateHelper.isConcurrentDisplayActive(display) + || mDeviceStateHelper.isRearDisplayOuterDefaultActive(display); + if (mKeyguardStateController.isOccluded() && deviceStateOccludesKeyguard) { if (DEBUG) { // When activities with FLAG_SHOW_WHEN_LOCKED are shown on top of Keyguard, the // Keyguard state becomes "occluded". In this case, we should not show the // KeyguardPresentation, since the activity is presenting content onto the // non-default display. - Log.i(TAG, "Do not show KeyguardPresentation when occluded and concurrent" + Log.i(TAG, "Do not show KeyguardPresentation when occluded and concurrent or rear" + " display is active"); } return false; @@ -326,44 +330,45 @@ public class KeyguardDisplayManager { public static class DeviceStateHelper implements DeviceStateManager.DeviceStateCallback { @Nullable - private final DisplayAddress.Physical mRearDisplayPhysicalAddress; - - // TODO(b/271317597): These device states should be defined in DeviceStateManager - private final int mConcurrentState; - private boolean mIsInConcurrentDisplayState; + private DeviceState mDeviceState; @Inject DeviceStateHelper( - @ShadeDisplayAware Context context, DeviceStateManager deviceStateManager, @Main Executor mainExecutor) { - - final String rearDisplayPhysicalAddress = context.getResources().getString( - com.android.internal.R.string.config_rearDisplayPhysicalAddress); - if (TextUtils.isEmpty(rearDisplayPhysicalAddress)) { - mRearDisplayPhysicalAddress = null; - } else { - mRearDisplayPhysicalAddress = DisplayAddress - .fromPhysicalDisplayId(Long.parseLong(rearDisplayPhysicalAddress)); - } - - mConcurrentState = context.getResources().getInteger( - com.android.internal.R.integer.config_deviceStateConcurrentRearDisplay); deviceStateManager.registerCallback(mainExecutor, this); } @Override public void onDeviceStateChanged(@NonNull DeviceState state) { - // When concurrent state ends, the display also turns off. This is enforced in various - // ExtensionRearDisplayPresentationTest CTS tests. So, we don't need to invoke - // hide() since that will happen through the onDisplayRemoved callback. - mIsInConcurrentDisplayState = state.getIdentifier() == mConcurrentState; + // When dual display or rear display mode ends, the display also turns off. This is + // enforced in various ExtensionRearDisplayPresentationTest CTS tests. So, we don't need + // to invoke hide() since that will happen through the onDisplayRemoved callback. + mDeviceState = state; + } + + /** + * @return true if the device is in Dual Display mode, and the specified display is the + * rear facing (outer) display. + */ + boolean isConcurrentDisplayActive(@NonNull Display display) { + return mDeviceState != null + && mDeviceState.hasProperty( + DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT) + && (display.getFlags() & Display.FLAG_REAR) != 0; } - boolean isConcurrentDisplayActive(Display display) { - return mIsInConcurrentDisplayState - && mRearDisplayPhysicalAddress != null - && mRearDisplayPhysicalAddress.equals(display.getAddress()); + /** + * @return true if the device is the updated Rear Display mode, and the specified display is + * the inner display. See {@link DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT}. + * Note that in this state, the outer display is the default display, while the inner + * display is the "rear" display. + */ + boolean isRearDisplayOuterDefaultActive(@NonNull Display display) { + return mDeviceState != null + && mDeviceState.hasProperty( + DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT) + && (display.getFlags() & Display.FLAG_REAR) != 0; } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt index 07bd813c2420..40a86dc3713e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt @@ -19,13 +19,12 @@ package com.android.keyguard import android.content.Context import android.view.View import com.android.systemui.customization.R as customR -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R -import com.android.systemui.shared.R as sharedR import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shared.R as sharedR import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START @@ -55,16 +54,17 @@ constructor( var statusViewCentered = false private val filterKeyguardAndSplitShadeOnly: () -> Boolean = { - statusBarStateController.getState() == KEYGUARD && !statusViewCentered } + statusBarStateController.getState() == KEYGUARD && !statusViewCentered + } private val filterKeyguard: () -> Boolean = { statusBarStateController.getState() == KEYGUARD } private val translateAnimator by lazy { - val smartSpaceViews = if (MigrateClocksToBlueprint.isEnabled) { - // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer] - val scrollXTranslation = { view: View, translation: Float -> - view.scrollX = -translation.toInt() - } + // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer] + val scrollXTranslation = { view: View, translation: Float -> + view.scrollX = -translation.toInt() + } + val smartSpaceViews = setOf( ViewIdToTranslate( viewId = sharedR.id.date_smartspace_view, @@ -83,18 +83,8 @@ constructor( direction = START, shouldBeAnimated = filterKeyguard, translateFunc = scrollXTranslation, - ) + ), ) - } else { - setOf(ViewIdToTranslate( - viewId = R.id.keyguard_status_area, - direction = START, - shouldBeAnimated = filterKeyguard, - translateFunc = { view, value -> - (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value - } - )) - } UnfoldConstantTranslateAnimator( viewsIdToTranslate = @@ -102,39 +92,39 @@ constructor( ViewIdToTranslate( viewId = customR.id.lockscreen_clock_view_large, direction = START, - shouldBeAnimated = filterKeyguardAndSplitShadeOnly + shouldBeAnimated = filterKeyguardAndSplitShadeOnly, ), ViewIdToTranslate( viewId = customR.id.lockscreen_clock_view, direction = START, - shouldBeAnimated = filterKeyguard + shouldBeAnimated = filterKeyguard, ), ViewIdToTranslate( viewId = R.id.notification_stack_scroller, direction = END, - shouldBeAnimated = filterKeyguardAndSplitShadeOnly - ) + shouldBeAnimated = filterKeyguardAndSplitShadeOnly, + ), ) + smartSpaceViews, - progressProvider = unfoldProgressProvider + progressProvider = unfoldProgressProvider, ) } private val shortcutButtonsAnimator by lazy { UnfoldConstantTranslateAnimator( viewsIdToTranslate = - setOf( - ViewIdToTranslate( - viewId = R.id.start_button, - direction = START, - shouldBeAnimated = filterKeyguard + setOf( + ViewIdToTranslate( + viewId = R.id.start_button, + direction = START, + shouldBeAnimated = filterKeyguard, + ), + ViewIdToTranslate( + viewId = R.id.end_button, + direction = END, + shouldBeAnimated = filterKeyguard, + ), ), - ViewIdToTranslate( - viewId = R.id.end_button, - direction = END, - shouldBeAnimated = filterKeyguard - ) - ), - progressProvider = unfoldProgressProvider + progressProvider = unfoldProgressProvider, ) } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index 0305b5e5ab63..e76f38c8c75c 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -26,7 +26,6 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; -import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.clocks.ClockMessageBuffers; import com.android.systemui.res.R; @@ -70,7 +69,7 @@ public abstract class ClockRegistryModule { context, layoutInflater, resources, - MigrateClocksToBlueprint.isEnabled(), + com.android.systemui.Flags.clockReactiveVariants() ), context.getString(R.string.lockscreen_clock_id_fallback), diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java index 4331f52eb1a2..a8870110da66 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java @@ -29,7 +29,7 @@ import dagger.Subcomponent; @Subcomponent(modules = {KeyguardUserSwitcherModule.class}) @KeyguardUserSwitcherScope public interface KeyguardQsUserSwitchComponent { - /** Simple factory for {@link KeyguardUserSwitcherComponent}. */ + /** Simple factory for {@link KeyguardQsUserSwitchComponent}. */ @Subcomponent.Factory interface Factory { KeyguardQsUserSwitchComponent build(@BindsInstance FrameLayout userAvatarContainer); diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java deleted file mode 100644 index 730c14dc9600..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherComponent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.keyguard.dagger; - -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; - -import dagger.BindsInstance; -import dagger.Subcomponent; - -/** - * Subcomponent for helping work with KeyguardUserSwitcher and its children. - */ -@Subcomponent(modules = {KeyguardUserSwitcherModule.class}) -@KeyguardUserSwitcherScope -public interface KeyguardUserSwitcherComponent { - /** Simple factory for {@link KeyguardUserSwitcherComponent}. */ - @Subcomponent.Factory - interface Factory { - KeyguardUserSwitcherComponent build( - @BindsInstance KeyguardUserSwitcherView keyguardUserSwitcherView); - } - - /** Builds a {@link com.android.systemui.statusbar.policy.KeyguardUserSwitcherController}. */ - KeyguardUserSwitcherController getKeyguardUserSwitcherController(); -} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java index b9184f405bf9..1ad2d4c5949a 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherModule.java @@ -18,7 +18,7 @@ package com.android.keyguard.dagger; import dagger.Module; -/** Dagger module for {@link KeyguardUserSwitcherComponent}. */ +/** Dagger module for {@link KeyguardQsUserSwitchComponent}. */ @Module public abstract class KeyguardUserSwitcherModule { } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java index 864472e53ce7..12d1949e30ba 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardUserSwitcherScope.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import javax.inject.Scope; /** - * Scope annotation for singleton items within the KeyguardUserSwitcherComponent. + * Scope annotation for singleton items within the KeyguardQsUserSwitchComponent. */ @Documented @Retention(RUNTIME) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java new file mode 100644 index 000000000000..7c141c1b561e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.hearingaid; + +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT; +import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.settingslib.bluetooth.AmbientVolumeUi; +import com.android.systemui.res.R; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.primitives.Ints; + +import java.util.Map; + +/** + * A view of ambient volume controls. + * + * <p> It consists of a header with an expand icon and volume sliders for unified control and + * separated control for devices in the same set. Toggle the expand icon will make the UI switch + * between unified and separated control. + */ +public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi { + + @Nullable + private AmbientVolumeUiListener mListener; + private ImageView mExpandIcon; + private ImageView mVolumeIcon; + private boolean mExpandable = true; + private boolean mExpanded = false; + private boolean mMutable = false; + private boolean mMuted = false; + private final BiMap<Integer, AmbientVolumeSlider> mSideToSliderMap = HashBiMap.create(); + private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT; + + private final AmbientVolumeSlider.OnChangeListener mSliderOnChangeListener = + (slider, value) -> { + if (mListener != null) { + final int side = mSideToSliderMap.inverse().get(slider); + mListener.onSliderValueChange(side, value); + } + }; + + public AmbientVolumeLayout(@Nullable Context context) { + this(context, /* attrs= */ null); + } + + public AmbientVolumeLayout(@Nullable Context context, @Nullable AttributeSet attrs) { + this(context, attrs, /* defStyleAttr= */ 0); + } + + public AmbientVolumeLayout(@Nullable Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + this(context, attrs, defStyleAttr, /* defStyleRes= */ 0); + } + + public AmbientVolumeLayout(@Nullable Context context, @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + inflate(context, R.layout.hearing_device_ambient_volume_layout, /* root= */ this); + init(); + } + + private void init() { + mVolumeIcon = requireViewById(R.id.ambient_volume_icon); + mVolumeIcon.setImageResource(com.android.settingslib.R.drawable.ic_ambient_volume); + mVolumeIcon.setOnClickListener(v -> { + if (!mMutable) { + return; + } + setMuted(!mMuted); + if (mListener != null) { + mListener.onAmbientVolumeIconClick(); + } + }); + updateVolumeIcon(); + + mExpandIcon = requireViewById(R.id.ambient_expand_icon); + mExpandIcon.setOnClickListener(v -> { + setExpanded(!mExpanded); + if (mListener != null) { + mListener.onExpandIconClick(); + } + }); + updateExpandIcon(); + } + + @Override + public void setVisible(boolean visible) { + setVisibility(visible ? VISIBLE : GONE); + } + + @Override + public void setExpandable(boolean expandable) { + mExpandable = expandable; + if (!mExpandable) { + setExpanded(false); + } + updateExpandIcon(); + } + + @Override + public boolean isExpandable() { + return mExpandable; + } + + @Override + public void setExpanded(boolean expanded) { + if (!mExpandable && expanded) { + return; + } + mExpanded = expanded; + updateExpandIcon(); + updateLayout(); + } + + @Override + public boolean isExpanded() { + return mExpanded; + } + + @Override + public void setMutable(boolean mutable) { + mMutable = mutable; + if (!mMutable) { + mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT; + setMuted(false); + } + updateVolumeIcon(); + } + + @Override + public boolean isMutable() { + return mMutable; + } + + @Override + public void setMuted(boolean muted) { + if (!mMutable && muted) { + return; + } + mMuted = muted; + if (mMutable && mMuted) { + for (AmbientVolumeSlider slider : mSideToSliderMap.values()) { + slider.setValue(slider.getMin()); + } + } + updateVolumeIcon(); + } + + @Override + public boolean isMuted() { + return mMuted; + } + + @Override + public void setListener(@Nullable AmbientVolumeUiListener listener) { + mListener = listener; + } + + @Override + public void setupSliders(@NonNull Map<Integer, BluetoothDevice> sideToDeviceMap) { + sideToDeviceMap.forEach((side, device) -> createSlider(side)); + createSlider(SIDE_UNIFIED); + + LinearLayout controlContainer = requireViewById(R.id.ambient_control_container); + controlContainer.removeAllViews(); + if (!mSideToSliderMap.isEmpty()) { + for (int side : VALID_SIDES) { + final AmbientVolumeSlider slider = mSideToSliderMap.get(side); + if (slider != null) { + controlContainer.addView(slider); + } + } + } + updateLayout(); + } + + @Override + public void setSliderEnabled(int side, boolean enabled) { + AmbientVolumeSlider slider = mSideToSliderMap.get(side); + if (slider != null && slider.isEnabled() != enabled) { + slider.setEnabled(enabled); + updateLayout(); + } + } + + @Override + public void setSliderValue(int side, int value) { + AmbientVolumeSlider slider = mSideToSliderMap.get(side); + if (slider != null && slider.getValue() != value) { + slider.setValue(value); + updateVolumeLevel(); + } + } + + @Override + public void setSliderRange(int side, int min, int max) { + AmbientVolumeSlider slider = mSideToSliderMap.get(side); + if (slider != null) { + slider.setMin(min); + slider.setMax(max); + } + } + + @Override + public void updateLayout() { + mSideToSliderMap.forEach((side, slider) -> { + if (side == SIDE_UNIFIED) { + slider.setVisibility(mExpanded ? GONE : VISIBLE); + } else { + slider.setVisibility(mExpanded ? VISIBLE : GONE); + } + if (!slider.isEnabled()) { + slider.setValue(slider.getMin()); + } + }); + updateVolumeLevel(); + } + + private void updateVolumeLevel() { + int leftLevel, rightLevel; + if (mExpanded) { + leftLevel = getVolumeLevel(SIDE_LEFT); + rightLevel = getVolumeLevel(SIDE_RIGHT); + } else { + final int unifiedLevel = getVolumeLevel(SIDE_UNIFIED); + leftLevel = unifiedLevel; + rightLevel = unifiedLevel; + } + mVolumeLevel = Ints.constrainToRange(leftLevel * 5 + rightLevel, + AMBIENT_VOLUME_LEVEL_MIN, AMBIENT_VOLUME_LEVEL_MAX); + updateVolumeIcon(); + } + + private int getVolumeLevel(int side) { + AmbientVolumeSlider slider = mSideToSliderMap.get(side); + if (slider == null || !slider.isEnabled()) { + return 0; + } + return slider.getVolumeLevel(); + } + + private void updateExpandIcon() { + mExpandIcon.setVisibility(mExpandable ? VISIBLE : GONE); + mExpandIcon.setRotation(mExpanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED); + if (mExpandable) { + final int stringRes = mExpanded ? R.string.hearing_devices_ambient_collapse_controls + : R.string.hearing_devices_ambient_expand_controls; + mExpandIcon.setContentDescription(mContext.getString(stringRes)); + } else { + mExpandIcon.setContentDescription(null); + } + } + + private void updateVolumeIcon() { + mVolumeIcon.setImageLevel(mMuted ? 0 : mVolumeLevel); + if (mMutable) { + final int stringRes = mMuted ? R.string.hearing_devices_ambient_unmute + : R.string.hearing_devices_ambient_mute; + mVolumeIcon.setContentDescription(mContext.getString(stringRes)); + mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } else { + mVolumeIcon.setContentDescription(null); + mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + } + } + + private void createSlider(int side) { + if (mSideToSliderMap.containsKey(side)) { + return; + } + AmbientVolumeSlider slider = new AmbientVolumeSlider(mContext); + slider.addOnChangeListener(mSliderOnChangeListener); + if (side == SIDE_LEFT) { + slider.setTitle(mContext.getString(R.string.hearing_devices_ambient_control_left)); + } else if (side == SIDE_RIGHT) { + slider.setTitle(mContext.getString(R.string.hearing_devices_ambient_control_right)); + } + mSideToSliderMap.put(side, slider); + } + + @VisibleForTesting + ImageView getVolumeIcon() { + return mVolumeIcon; + } + + @VisibleForTesting + ImageView getExpandIcon() { + return mExpandIcon; + } + + @VisibleForTesting + Map<Integer, AmbientVolumeSlider> getSliders() { + return mSideToSliderMap; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java new file mode 100644 index 000000000000..92338ef3773c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.hearingaid; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.systemui.res.R; + +import com.google.android.material.slider.Slider; + +import java.util.ArrayList; +import java.util.List; + +/** + * A view of ambient volume slider. + * <p> It consists by a title {@link TextView} with a volume control {@link Slider}. + */ +public class AmbientVolumeSlider extends LinearLayout { + + private final TextView mTitle; + private final Slider mSlider; + private final List<OnChangeListener> mChangeListeners = new ArrayList<>(); + private final Slider.OnSliderTouchListener mSliderTouchListener = + new Slider.OnSliderTouchListener() { + @Override + public void onStartTrackingTouch(@NonNull Slider slider) { + } + + @Override + public void onStopTrackingTouch(@NonNull Slider slider) { + final int value = Math.round(slider.getValue()); + for (OnChangeListener listener : mChangeListeners) { + listener.onValueChange(AmbientVolumeSlider.this, value); + } + } + }; + public AmbientVolumeSlider(@Nullable Context context) { + this(context, /* attrs= */ null); + } + + public AmbientVolumeSlider(@Nullable Context context, @Nullable AttributeSet attrs) { + this(context, attrs, /* defStyleAttr= */ 0); + } + + public AmbientVolumeSlider(@Nullable Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + this(context, attrs, defStyleAttr, /* defStyleRes= */ 0); + } + + public AmbientVolumeSlider(@Nullable Context context, @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + inflate(context, R.layout.hearing_device_ambient_volume_slider, /* root= */ this); + mTitle = requireViewById(R.id.ambient_volume_slider_title); + mSlider = requireViewById(R.id.ambient_volume_slider); + mSlider.addOnSliderTouchListener(mSliderTouchListener); + } + + /** + * Sets title for the ambient volume slider. + * <p> If text is null or empty, then {@link TextView} is hidden. + */ + public void setTitle(@Nullable String text) { + mTitle.setText(text); + mTitle.setVisibility(TextUtils.isEmpty(text) ? GONE : VISIBLE); + } + + /** Gets title for the ambient volume slider. */ + public CharSequence getTitle() { + return mTitle.getText(); + } + + /** + * Adds the callback to the ambient volume slider to get notified when the value is changed by + * user. + * <p> Note: The {@link OnChangeListener#onValueChange(AmbientVolumeSlider, int)} will be + * called when user's finger take off from the slider. + */ + public void addOnChangeListener(@Nullable OnChangeListener listener) { + if (listener == null) { + return; + } + mChangeListeners.add(listener); + } + + /** Sets max value to the ambient volume slider. */ + public void setMax(float max) { + mSlider.setValueTo(max); + } + + /** Gets max value from the ambient volume slider. */ + public float getMax() { + return mSlider.getValueTo(); + } + + /** Sets min value to the ambient volume slider. */ + public void setMin(float min) { + mSlider.setValueFrom(min); + } + + /** Gets min value from the ambient volume slider. */ + public float getMin() { + return mSlider.getValueFrom(); + } + + /** Sets value to the ambient volume slider. */ + public void setValue(float value) { + mSlider.setValue(value); + } + + /** Gets value from the ambient volume slider. */ + public float getValue() { + return mSlider.getValue(); + } + + /** Sets the enable state to the ambient volume slider. */ + public void setEnabled(boolean enabled) { + mSlider.setEnabled(enabled); + } + + /** Gets the enable state of the ambient volume slider. */ + public boolean isEnabled() { + return mSlider.isEnabled(); + } + + /** + * Gets the volume value of the ambient volume slider. + * <p> The volume level is divided into 5 levels: + * Level 0 corresponds to the minimum volume value. The range between the minimum and maximum + * volume is divided into 4 equal intervals, represented by levels 1 to 4. + */ + public int getVolumeLevel() { + if (!mSlider.isEnabled()) { + return 0; + } + final double min = mSlider.getValueFrom(); + final double max = mSlider.getValueTo(); + final double levelGap = (max - min) / 4.0; + final double value = mSlider.getValue(); + return (int) Math.ceil((value - min) / levelGap); + } + + /** Interface definition for a callback invoked when a slider's value is changed. */ + public interface OnChangeListener { + /** Called when the finger is take off from the slider. */ + void onValueChange(@NonNull AmbientVolumeSlider slider, int value); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java index 56435df1ad2c..73aabc3cf95a 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java @@ -52,10 +52,12 @@ import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.android.settingslib.bluetooth.AmbientVolumeUiController; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.accessibility.hearingaid.HearingDevicesListAdapter.HearingDeviceItemCallback; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.bluetooth.qsdialog.ActiveHearingDeviceItemFactory; @@ -108,7 +110,6 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, private SystemUIDialog mDialog; - private RecyclerView mDeviceList; private List<DeviceItem> mHearingDeviceItemList; private HearingDevicesListAdapter mDeviceListAdapter; @@ -134,6 +135,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } }; + private AmbientVolumeUiController mAmbientController; + private final List<DeviceItemFactory> mHearingDeviceItemFactoryList = List.of( new ActiveHearingDeviceItemFactory(), new AvailableHearingDeviceItemFactory(), @@ -225,13 +228,17 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, public void onActiveDeviceChanged(@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) { refreshDeviceUi(); - if (mPresetController != null) { - mPresetController.setDevice(getActiveHearingDevice()); - mMainHandler.post(() -> { + mMainHandler.post(() -> { + CachedBluetoothDevice device = getActiveHearingDevice(); + if (mPresetController != null) { + mPresetController.setDevice(device); mPresetLayout.setVisibility( mPresetController.isPresetControlAvailable() ? VISIBLE : GONE); - }); - } + } + if (mAmbientController != null) { + mAmbientController.loadDevice(device); + } + }); } @Override @@ -272,13 +279,13 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId); - mDeviceList = dialog.requireViewById(R.id.device_list); - mPresetLayout = dialog.requireViewById(R.id.preset_layout); - mPresetSpinner = dialog.requireViewById(R.id.preset_spinner); setupDeviceListView(dialog); - setupPresetSpinner(dialog); setupPairNewDeviceButton(dialog); + setupPresetSpinner(dialog); + if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) { + setupAmbientControls(); + } if (com.android.systemui.Flags.hearingDevicesDialogRelatedTools()) { setupRelatedToolsView(dialog); } @@ -286,41 +293,50 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, @Override public void onStart(@NonNull SystemUIDialog dialog) { - if (mLocalBluetoothManager == null) { - return; - } - mLocalBluetoothManager.getEventManager().registerCallback(this); - if (mPresetController != null) { - mPresetController.registerHapCallback(); - } + ThreadUtils.postOnBackgroundThread(() -> { + if (mLocalBluetoothManager != null) { + mLocalBluetoothManager.getEventManager().registerCallback(this); + } + if (mPresetController != null) { + mPresetController.registerHapCallback(); + } + if (mAmbientController != null) { + mAmbientController.start(); + } + }); } @Override public void onStop(@NonNull SystemUIDialog dialog) { - if (mLocalBluetoothManager == null) { - return; - } - - if (mPresetController != null) { - mPresetController.unregisterHapCallback(); - } - mLocalBluetoothManager.getEventManager().unregisterCallback(this); + ThreadUtils.postOnBackgroundThread(() -> { + if (mLocalBluetoothManager != null) { + mLocalBluetoothManager.getEventManager().unregisterCallback(this); + } + if (mPresetController != null) { + mPresetController.unregisterHapCallback(); + } + if (mAmbientController != null) { + mAmbientController.stop(); + } + }); } private void setupDeviceListView(SystemUIDialog dialog) { - mDeviceList.setLayoutManager(new LinearLayoutManager(dialog.getContext())); + final RecyclerView deviceList = dialog.requireViewById(R.id.device_list); + deviceList.setLayoutManager(new LinearLayoutManager(dialog.getContext())); mHearingDeviceItemList = getHearingDeviceItemList(); mDeviceListAdapter = new HearingDevicesListAdapter(mHearingDeviceItemList, this); - mDeviceList.setAdapter(mDeviceListAdapter); + deviceList.setAdapter(mDeviceListAdapter); } private void setupPresetSpinner(SystemUIDialog dialog) { mPresetController = new HearingDevicesPresetsController(mProfileManager, mPresetCallback); mPresetController.setDevice(getActiveHearingDevice()); + mPresetSpinner = dialog.requireViewById(R.id.preset_spinner); mPresetInfoAdapter = new HearingDevicesSpinnerAdapter(dialog.getContext()); mPresetSpinner.setAdapter(mPresetInfoAdapter); - // disable redundant Touch & Hold accessibility action for Switch Access + // Disable redundant Touch & Hold accessibility action for Switch Access mPresetSpinner.setAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(@NonNull View host, @@ -349,12 +365,20 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } }); + mPresetLayout = dialog.requireViewById(R.id.preset_layout); mPresetLayout.setVisibility(mPresetController.isPresetControlAvailable() ? VISIBLE : GONE); } + private void setupAmbientControls() { + final AmbientVolumeLayout ambientLayout = mDialog.requireViewById(R.id.ambient_layout); + mAmbientController = new AmbientVolumeUiController( + mDialog.getContext(), mLocalBluetoothManager, ambientLayout); + mAmbientController.setShowUiWhenLocalDataExist(false); + mAmbientController.loadDevice(getActiveHearingDevice()); + } + private void setupPairNewDeviceButton(SystemUIDialog dialog) { final Button pairButton = dialog.requireViewById(R.id.pair_new_device_button); - pairButton.setVisibility(mShowPairNewDevice ? VISIBLE : GONE); if (mShowPairNewDevice) { pairButton.setOnClickListener(v -> { diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt index 232b62985ad0..11a6cb9334ae 100644 --- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt @@ -21,8 +21,11 @@ import android.window.OnBackAnimationCallback import android.window.OnBackInvokedCallback import android.window.OnBackInvokedDispatcher import android.window.WindowOnBackInvokedDispatcher +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.CoreStartable +import com.android.systemui.Flags.glanceableHubBackAction import com.android.systemui.Flags.predictiveBackAnimateShade +import com.android.systemui.communal.domain.interactor.CommunalBackActionInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -35,7 +38,6 @@ import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import com.android.app.tracing.coroutines.launchTraced as launch /** Handles requests to go back either from a button or gesture. */ @SysUISingleton @@ -50,6 +52,7 @@ constructor( private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor, private val shadeBackActionInteractor: ShadeBackActionInteractor, private val qsController: QuickSettingsController, + private val communalBackActionInteractor: CommunalBackActionInteractor, ) : CoreStartable { private var isCallbackRegistered = false @@ -111,8 +114,11 @@ constructor( shadeBackActionInteractor.animateCollapseQs(false) return true } - if (shadeBackActionInteractor.closeUserSwitcherIfOpen()) { - return true + if (glanceableHubBackAction()) { + if (communalBackActionInteractor.canBeDismissed()) { + communalBackActionInteractor.onBackPressed() + return true + } } if (shouldBackBeHandled()) { if (shadeBackActionInteractor.canBeCollapsed()) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index 4c2dc41fb759..d8c628fd680b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -155,6 +155,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at override fun onAnimationEnd(animation: Animator) { drawDwell = false resetDwellAlpha() + invalidate() } }) start() @@ -191,6 +192,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at override fun onAnimationEnd(animation: Animator) { drawDwell = false resetDwellAlpha() + invalidate() } }) start() @@ -248,6 +250,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at override fun onAnimationEnd(animation: Animator) { drawDwell = false + invalidate() } }) start() diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt index 9cfb5be478ed..b294dd1b0b71 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt @@ -41,6 +41,7 @@ import com.android.internal.R as InternalR import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.time.SystemClock import dagger.assisted.Assisted @@ -68,6 +69,7 @@ internal constructor( private val uiEventLogger: UiEventLogger, private val logger: BluetoothTileDialogLogger, private val systemuiDialogFactory: SystemUIDialog.Factory, + private val shadeDialogContextInteractor: ShadeDialogContextInteractor, ) : SystemUIDialog.Delegate { private val mutableBluetoothStateToggle: MutableStateFlow<Boolean?> = MutableStateFlow(null) @@ -105,7 +107,7 @@ internal constructor( } override fun createDialog(): SystemUIDialog { - return systemuiDialogFactory.create(this) + return systemuiDialogFactory.create(this, shadeDialogContextInteractor.context) } override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { @@ -405,10 +407,11 @@ internal constructor( } // updating icon colors - val tintColor = context.getColor( - if (item.isActive) InternalR.color.materialColorOnPrimaryContainer - else InternalR.color.materialColorOnSurface - ) + val tintColor = + context.getColor( + if (item.isActive) InternalR.color.materialColorOnPrimaryContainer + else InternalR.color.materialColorOnSurface + ) // update icons iconView.apply { diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt index aef5f1f422d1..e6f02457d320 100644 --- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt +++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt @@ -21,14 +21,17 @@ import android.graphics.drawable.Drawable /** * Models an icon, that can either be already [loaded][Icon.Loaded] or be a [reference] - * [Icon.Resource] to a resource. + * [Icon.Resource] to a resource. In case of [Loaded], the resource ID [res] is optional. */ sealed class Icon { abstract val contentDescription: ContentDescription? - data class Loaded( + data class Loaded + @JvmOverloads + constructor( val drawable: Drawable, override val contentDescription: ContentDescription?, + @DrawableRes val res: Int? = null, ) : Icon() data class Resource( @@ -37,6 +40,11 @@ sealed class Icon { ) : Icon() } -/** Creates [Icon.Loaded] for a given drawable with an optional [contentDescription]. */ -fun Drawable.asIcon(contentDescription: ContentDescription? = null): Icon.Loaded = - Icon.Loaded(this, contentDescription) +/** + * Creates [Icon.Loaded] for a given drawable with an optional [contentDescription] and an optional + * [res]. + */ +fun Drawable.asIcon( + contentDescription: ContentDescription? = null, + @DrawableRes res: Int? = null, +): Icon.Loaded = Icon.Loaded(this, contentDescription, res) 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 26abb48ce7db..73c0179cf8ec 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 @@ -55,6 +55,8 @@ interface CommunalSettingsRepository { /** A [CommunalEnabledState] for the specified user. */ fun getEnabledState(user: UserInfo): Flow<CommunalEnabledState> + fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * @@ -138,6 +140,20 @@ constructor( .flowOn(bgDispatcher) } + override fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> = + secureSettings + .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.SCREENSAVER_ENABLED)) + // Force an update + .onStart { emit(Unit) } + .map { + secureSettings.getIntForUser( + Settings.Secure.SCREENSAVER_ENABLED, + SCREENSAVER_ENABLED_SETTING_DEFAULT, + user.id, + ) == 1 + } + .flowOn(bgDispatcher) + override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( @@ -182,6 +198,7 @@ constructor( companion object { const val GLANCEABLE_HUB_BACKGROUND_SETTING = "glanceable_hub_background" private const val ENABLED_SETTING_DEFAULT = 1 + private const val SCREENSAVER_ENABLED_SETTING_DEFAULT = 0 } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt new file mode 100644 index 000000000000..2ccf96abff79 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractor.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.domain.interactor + +import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes +import javax.inject.Inject + +/** + * {@link CommunalBackActionInteractor} is responsible for handling back gestures on the glanceable + * hub. When invoked SystemUI should navigate back to the lockscreen. + */ +@SysUISingleton +class CommunalBackActionInteractor +@Inject +constructor( + private val communalInteractor: CommunalInteractor, + private val communalSceneInteractor: CommunalSceneInteractor, + private val sceneInteractor: SceneInteractor, +) { + fun canBeDismissed(): Boolean { + return communalInteractor.isCommunalShowing.value + } + + fun onBackPressed() { + if (SceneContainerFlag.isEnabled) { + // TODO(b/384610333): Properly determine whether to go to dream or lockscreen on back. + sceneInteractor.changeScene( + toScene = Scenes.Lockscreen, + loggingReason = "CommunalBackActionInteractor", + ) + } else { + communalSceneInteractor.changeScene( + newScene = CommunalScenes.Blank, + loggingReason = "CommunalBackActionInteractor", + ) + } + } +} 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 ea428698e476..947113da0e60 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 @@ -285,7 +285,7 @@ constructor( * use [isIdleOnCommunal]. */ // TODO(b/323215860): rename to something more appropriate after cleaning up usages - val isCommunalShowing: Flow<Boolean> = + val isCommunalShowing: StateFlow<Boolean> = flow { emit(SceneContainerFlag.isEnabled) } .flatMapLatest { sceneContainerEnabled -> if (sceneContainerEnabled) { @@ -304,10 +304,10 @@ constructor( columnName = "isCommunalShowing", initialValue = false, ) - .shareIn( + .stateIn( scope = applicationScope, - started = SharingStarted.WhileSubscribed(), - replay = 1, + started = SharingStarted.Eagerly, + initialValue = false, ) /** 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 862b05bc9b5d..c1f21e4046a3 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 @@ -69,6 +69,12 @@ constructor( // Start this eagerly since the value is accessed synchronously in many places. .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) + /** Whether or not screensaver (dreams) is enabled for the currently selected user. */ + val isScreensaverEnabled: Flow<Boolean> = + userInteractor.selectedUserInfo.flatMapLatest { user -> + repository.getScreensaverEnabledState(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/ui/viewmodel/CommunalAppWidgetViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModel.kt index 6bafd14f9359..051cb4107328 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalAppWidgetViewModel.kt @@ -83,7 +83,7 @@ constructor( } private suspend fun handleSetListener(appWidgetId: Int, listener: AppWidgetHostListener) = - withContextTraced("$TAG#setListenerInner", backgroundContext) { + withContextTraced("${TAG}_$appWidgetId#setListenerInner", backgroundContext) { if ( multiUserHelper.glanceableHubHsumFlagEnabled && multiUserHelper.isInHeadlessSystemUser() @@ -92,13 +92,19 @@ constructor( // remotely in the foreground user, and therefore the host listener needs to be // registered through the widget manager. with(glanceableHubWidgetManagerLazy.get()) { - setAppWidgetHostListener(appWidgetId, listenerDelegateFactory.create(listener)) + setAppWidgetHostListener( + appWidgetId, + listenerDelegateFactory.create("${TAG}_$appWidgetId", listener), + ) } } else { // Instead of setting the view as the listener directly, we wrap the view in a // delegate which ensures the callbacks always get called on the main thread. with(appWidgetHostLazy.get()) { - setListener(appWidgetId, listenerDelegateFactory.create(listener)) + setListener( + appWidgetId, + listenerDelegateFactory.create("${TAG}_$appWidgetId", listener), + ) } } } 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 7d5b196dfaa8..c6f96e198b91 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 @@ -18,10 +18,15 @@ package com.android.systemui.communal.ui.viewmodel import android.annotation.SuppressLint import android.app.DreamManager +import android.content.Intent +import android.provider.Settings +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.kotlin.isDevicePluggedIn +import com.android.systemui.util.kotlin.sample import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlin.coroutines.CoroutineContext @@ -31,7 +36,6 @@ 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 @@ -41,6 +45,8 @@ class CommunalToDreamButtonViewModel constructor( @Background private val backgroundContext: CoroutineContext, batteryController: BatteryController, + private val settingsInteractor: CommunalSettingsInteractor, + private val activityStarter: ActivityStarter, private val dreamManager: DreamManager, ) : ExclusiveActivatable() { @@ -49,11 +55,7 @@ constructor( /** Whether we should show a button on hub to switch to dream. */ @SuppressLint("MissingPermission") val shouldShowDreamButtonOnHub = - batteryController - .isDevicePluggedIn() - .distinctUntilChanged() - .map { isPluggedIn -> isPluggedIn && dreamManager.canStartDreaming(true) } - .flowOn(backgroundContext) + batteryController.isDevicePluggedIn().distinctUntilChanged().flowOn(backgroundContext) /** Handle a tap on the "show dream" button. */ fun onShowDreamButtonTap() { @@ -63,9 +65,21 @@ constructor( @SuppressLint("MissingPermission") override suspend fun onActivated(): Nothing = coroutineScope { launch { - _requests.receiveAsFlow().collectLatest { - withContext(backgroundContext) { dreamManager.startDream() } - } + _requests + .receiveAsFlow() + .sample(settingsInteractor.isScreensaverEnabled) + .collectLatest { enabled -> + withContext(backgroundContext) { + if (enabled) { + dreamManager.startDream() + } else { + activityStarter.postStartActivityDismissingKeyguard( + Intent(Settings.ACTION_DREAM_SETTINGS), + 0, + ) + } + } + } } awaitCancellation() diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt index 7d80acd1f439..c0f7caa8b275 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt @@ -19,11 +19,12 @@ package com.android.systemui.communal.widgets import android.appwidget.AppWidgetHost.AppWidgetHostListener import android.appwidget.AppWidgetProviderInfo import android.widget.RemoteViews -import com.android.systemui.dagger.qualifiers.Main +import com.android.app.tracing.coroutines.launchTraced +import com.android.systemui.dagger.qualifiers.Application import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import java.util.concurrent.Executor +import kotlinx.coroutines.CoroutineScope /** * Wrapper for an [AppWidgetHostListener] to ensure the callbacks are executed on the main thread. @@ -31,24 +32,27 @@ import java.util.concurrent.Executor class AppWidgetHostListenerDelegate @AssistedInject constructor( - @Main private val mainExecutor: Executor, + @Application private val mainScope: CoroutineScope, + @Assisted private val tag: String, @Assisted private val listener: AppWidgetHostListener, ) : AppWidgetHostListener { @AssistedFactory fun interface Factory { - fun create(listener: AppWidgetHostListener): AppWidgetHostListenerDelegate + fun create(tag: String, listener: AppWidgetHostListener): AppWidgetHostListenerDelegate } override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) { - mainExecutor.execute { listener.onUpdateProviderInfo(appWidget) } + mainScope.launchTraced("$tag#onUpdateProviderInfo") { + listener.onUpdateProviderInfo(appWidget) + } } override fun updateAppWidget(views: RemoteViews?) { - mainExecutor.execute { listener.updateAppWidget(views) } + mainScope.launchTraced("$tag#updateAppWidget") { listener.updateAppWidget(views) } } override fun onViewDataChanged(viewId: Int) { - mainExecutor.execute { listener.onViewDataChanged(viewId) } + mainScope.launchTraced("$tag#onViewDataChanged") { listener.onViewDataChanged(viewId) } } } diff --git a/packages/SystemUI/src/com/android/systemui/compose/ComposeModule.kt b/packages/SystemUI/src/com/android/systemui/compose/ComposeModule.kt new file mode 100644 index 000000000000..31b6f0ff90fd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/compose/ComposeModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.compose + +import com.android.systemui.CoreStartable +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +interface ComposeModule { + @Binds + @IntoMap + @ClassKey(ComposeTracingStartable::class) + fun composeTracing(impl: ComposeTracingStartable): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/compose/ComposeTracingStartable.kt b/packages/SystemUI/src/com/android/systemui/compose/ComposeTracingStartable.kt new file mode 100644 index 000000000000..a015900d0817 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/compose/ComposeTracingStartable.kt @@ -0,0 +1,106 @@ +/* + * 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(InternalComposeTracingApi::class) + +package com.android.systemui.compose + +import android.os.Trace +import android.util.Log +import androidx.compose.runtime.Composer +import androidx.compose.runtime.CompositionTracer +import androidx.compose.runtime.InternalComposeTracingApi +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.commandline.Command +import com.android.systemui.statusbar.commandline.CommandRegistry +import com.android.systemui.statusbar.commandline.ParseableCommand +import java.io.PrintWriter +import javax.inject.Inject + +private const val TAG = "ComposeTracingStartable" +private const val COMMAND_NAME = "composition-tracing" +private const val SUBCOMMAND_ENABLE = "enable" +private const val SUBCOMMAND_DISABLE = "disable" + +/** + * Sets up a [Command] to enable or disable Composition tracing. + * + * Usage: + * ``` + * adb shell cmd statusbar composition-tracing [enable|disable] + * ${ANDROID_BUILD_TOP}/external/perfetto/tools/record_android_trace -c ${ANDROID_BUILD_TOP}/prebuilts/tools/linux-x86_64/perfetto/configs/trace_config_detailed.textproto + * ``` + */ +@SysUISingleton +class ComposeTracingStartable @Inject constructor(private val commandRegistry: CommandRegistry) : + CoreStartable { + @OptIn(InternalComposeTracingApi::class) + override fun start() { + Log.i(TAG, "Set up Compose tracing command") + commandRegistry.registerCommand(COMMAND_NAME) { CompositionTracingCommand() } + } +} + +private class CompositionTracingCommand : ParseableCommand(COMMAND_NAME) { + val enable by subCommand(EnableCommand()) + val disable by subCommand(DisableCommand()) + + override fun execute(pw: PrintWriter) { + if ((enable != null) xor (disable != null)) { + enable?.execute(pw) + disable?.execute(pw) + } else { + help(pw) + } + } +} + +private class EnableCommand : ParseableCommand(SUBCOMMAND_ENABLE) { + override fun execute(pw: PrintWriter) { + val msg = "Enabled Composition tracing" + Log.i(TAG, msg) + pw.println(msg) + enableCompositionTracing() + } + + private fun enableCompositionTracing() { + Composer.setTracer( + object : CompositionTracer { + override fun traceEventStart(key: Int, dirty1: Int, dirty2: Int, info: String) { + Trace.traceBegin(Trace.TRACE_TAG_APP, info) + } + + override fun traceEventEnd() = Trace.traceEnd(Trace.TRACE_TAG_APP) + + override fun isTraceInProgress(): Boolean = Trace.isEnabled() + } + ) + } +} + +private class DisableCommand : ParseableCommand(SUBCOMMAND_DISABLE) { + override fun execute(pw: PrintWriter) { + val msg = "Disabled Composition tracing" + Log.i(TAG, msg) + pw.println(msg) + disableCompositionTracing() + } + + private fun disableCompositionTracing() { + Composer.setTracer(null) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 9ae106c3ab39..014c0db618e1 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -267,6 +267,7 @@ public class FrameworkServicesModule { } @Provides + @Nullable @Singleton static VirtualDeviceManager provideVirtualDeviceManager(Context context) { return context.getSystemService(VirtualDeviceManager.class); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index d6f8957ace33..7ebe52f3bd58 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -54,6 +54,7 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryMod import com.android.systemui.common.usagestats.data.CommonUsageStatsDataLayerModule; import com.android.systemui.communal.dagger.CommunalModule; import com.android.systemui.complication.dagger.ComplicationComponent; +import com.android.systemui.compose.ComposeModule; import com.android.systemui.controls.dagger.ControlsModule; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Main; @@ -133,6 +134,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; @@ -141,7 +143,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.ConfigurationControllerModule; import com.android.systemui.statusbar.phone.LetterboxModule; import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.PolicyModule; import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController; @@ -214,6 +215,7 @@ import javax.inject.Named; ClockRegistryModule.class, CommunalModule.class, CommonDataLayerModule.class, + ComposeModule.class, ConfigurationModule.class, ConfigurationRepositoryModule.class, CommonUsageStatsDataLayerModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 571b37f43fd4..b272d65a8a11 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -54,6 +54,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.PhoneWindow; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.Flags; import com.android.systemui.ambient.touch.TouchHandler; import com.android.systemui.ambient.touch.TouchMonitor; import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent; @@ -210,6 +211,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mCommunalVisible = communalVisible; updateLifecycleStateLocked(); + updateGestureBlockingLocked(); }); } }; @@ -585,7 +587,8 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ private void updateGestureBlockingLocked() { final boolean shouldBlock = mStarted && !mShadeExpanded && !mBouncerShowing - && !isDreamInPreviewMode(); + && !isDreamInPreviewMode() + && !(Flags.glanceableHubBackAction() && mCommunalVisible); if (shouldBlock) { mGestureInteractor.addGestureBlockedMatcher(DREAM_TYPE_MATCHER, diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt index eaf5eac155ef..73968da38088 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt @@ -126,24 +126,24 @@ interface ServerFlagReaderModule { } class ServerFlagReaderFake : ServerFlagReader { - private val flagMap: MutableMap<String, Boolean> = mutableMapOf() + private val flagMap: MutableMap<Pair<String, String>, Boolean> = mutableMapOf() private val listeners = mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() override fun hasOverride(namespace: String, name: String): Boolean { - return flagMap.containsKey(name) + return flagMap.containsKey(namespace to name) } override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean { - return flagMap.getOrDefault(name, default) + return flagMap.getOrDefault(namespace to name, default) } fun setFlagValue(namespace: String, name: String, value: Boolean) { - flagMap.put(name, value) + flagMap.put(namespace to name, value) for ((listener, flags) in listeners) { flagLoop@ for (flag in flags) { - if (name == flag.name) { + if (namespace == flag.namespace && name == flag.name) { listener.onChange(flag, if (value) "true" else "false") break@flagLoop } @@ -152,13 +152,13 @@ class ServerFlagReaderFake : ServerFlagReader { } fun eraseFlag(namespace: String, name: String) { - flagMap.remove(name) + flagMap.remove(namespace to name) } override fun listenForChanges( flags: Collection<Flag<*>>, listener: ServerFlagReader.ChangeListener ) { - listeners.add(Pair(listener, flags)) + listeners.add(listener to flags) } } diff --git a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt index 62ab18bbb738..9e89ed987c36 100644 --- a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt +++ b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt @@ -17,26 +17,40 @@ package com.android.systemui.grid.ui.compose import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.IntrinsicMeasurable import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.Placeable +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.ParentDataModifierNode import androidx.compose.ui.semantics.CollectionInfo -import androidx.compose.ui.semantics.CollectionItemInfo import androidx.compose.ui.semantics.collectionInfo -import androidx.compose.ui.semantics.collectionItemInfo import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Constraints +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 androidx.compose.ui.util.fastMap +import androidx.compose.ui.util.fastMapIndexed import kotlin.math.max +/** Creates a [SpannedGridState] that is remembered across recompositions. */ +@Composable +fun rememberSpannedGridState(): SpannedGridState { + return remember { SpannedGridStateImpl() } +} + /** - * Horizontal (non lazy) grid that supports [spans] for its elements. + * Horizontal (non lazy) grid that supports spans for its elements. * * The elements will be laid down vertically first, and then by columns. So assuming LTR layout, it * will be (for a span list `[2, 1, 2, 1, 1, 1, 1, 1]` and 4 rows): @@ -50,8 +64,11 @@ import kotlin.math.max * where repeated numbers show larger span. If an element doesn't fit in a column due to its span, * it will start a new column. * - * Elements in [spans] must be in the interval `[1, rows]` ([rows] > 0), and the composables are - * associated with the corresponding span based on their index. + * Elements in [composables] can provide their span using [SpannedGridScope.span] and have a default + * span of 1. Spans must be in the interval `[1, columns]` ([columns] > 0). + * + * Passing a [SpannedGridState] can be useful to get access to the [SpannedGridState.positions], + * representing the row and column of each item. * * Due to the fact that elements are seen as a linear list that's laid out in a grid, the semantics * represent the collection as a list of elements. @@ -61,23 +78,23 @@ fun HorizontalSpannedGrid( rows: Int, columnSpacing: Dp, rowSpacing: Dp, - spans: List<Int>, modifier: Modifier = Modifier, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + state: SpannedGridState = rememberSpannedGridState(), + composables: @Composable SpannedGridScope.() -> Unit, ) { SpannedGrid( primarySpaces = rows, crossAxisSpacing = rowSpacing, mainAxisSpacing = columnSpacing, - spans = spans, isVertical = false, + state = state, modifier = modifier, composables = composables, ) } /** - * Horizontal (non lazy) grid that supports [spans] for its elements. + * Horizontal (non lazy) grid that supports spans for its elements. * * The elements will be laid down horizontally first, and then by rows. So assuming LTR layout, it * will be (for a span list `[2, 1, 2, 1, 1, 1, 1, 1]` and 4 columns): @@ -90,8 +107,11 @@ fun HorizontalSpannedGrid( * where repeated numbers show larger span. If an element doesn't fit in a row due to its span, it * will start a new row. * - * Elements in [spans] must be in the interval `[1, columns]` ([columns] > 0), and the composables - * are associated with the corresponding span based on their index. + * Elements in [composables] can provide their span using [SpannedGridScope.span] and have a default + * span of 1. Spans must be in the interval `[1, columns]` ([columns] > 0). + * + * Passing a [SpannedGridState] can be useful to get access to the [SpannedGridState.positions], + * representing the row and column of each item. * * Due to the fact that elements are seen as a linear list that's laid out in a grid, the semantics * represent the collection as a list of elements. @@ -101,16 +121,16 @@ fun VerticalSpannedGrid( columns: Int, columnSpacing: Dp, rowSpacing: Dp, - spans: List<Int>, modifier: Modifier = Modifier, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + state: SpannedGridState = rememberSpannedGridState(), + composables: @Composable SpannedGridScope.() -> Unit, ) { SpannedGrid( primarySpaces = columns, crossAxisSpacing = columnSpacing, mainAxisSpacing = rowSpacing, - spans = spans, isVertical = true, + state = state, modifier = modifier, composables = composables, ) @@ -121,18 +141,15 @@ private fun SpannedGrid( primarySpaces: Int, crossAxisSpacing: Dp, mainAxisSpacing: Dp, - spans: List<Int>, isVertical: Boolean, + state: SpannedGridState, modifier: Modifier = Modifier, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + composables: @Composable SpannedGridScope.() -> Unit, ) { + state as SpannedGridStateImpl + SideEffect { state.setOrientation(isVertical) } + val crossAxisArrangement = Arrangement.spacedBy(crossAxisSpacing) - spans.forEachIndexed { index, span -> - check(span in 1..primarySpaces) { - "Span out of bounds. Span at index $index has value of $span which is outside of the " + - "expected rance of [1, $primarySpaces]" - } - } if (isVertical) { check(crossAxisSpacing >= 0.dp) { "Negative columnSpacing $crossAxisSpacing" } @@ -142,21 +159,6 @@ private fun SpannedGrid( check(crossAxisSpacing >= 0.dp) { "Negative rowSpacing $crossAxisSpacing" } } - val totalMainAxisGroups: Int = - remember(primarySpaces, spans) { - var currentAccumulated = 0 - var groups = 1 - spans.forEach { span -> - if (currentAccumulated + span <= primarySpaces) { - currentAccumulated += span - } else { - groups += 1 - currentAccumulated = span - } - } - groups - } - val slotPositionsAndSizesCache = remember { object { var sizes = IntArray(0) @@ -165,25 +167,28 @@ private fun SpannedGrid( } Layout( - { - (0 until spans.size).map { spanIndex -> - Box( - Modifier.semantics { - collectionItemInfo = - if (isVertical) { - CollectionItemInfo(spanIndex, 1, 0, 1) - } else { - CollectionItemInfo(0, 1, spanIndex, 1) - } + { SpannedGridScope.composables() }, + modifier.semantics { collectionInfo = CollectionInfo(state.positions.size, 1) }, + ) { measurables, constraints -> + val spans = + measurables.fastMapIndexed { index, measurable -> + measurable.spannedGridParentData.span.also { span -> + check(span in 1..primarySpaces) { + "Span out of bounds. Span at index $index has value of $span which is " + + "outside of the expected rance of [1, $primarySpaces]" } - ) { - composables(spanIndex) } } - }, - modifier.semantics { collectionInfo = CollectionInfo(spans.size, 1) }, - ) { measurables, constraints -> - check(measurables.size == spans.size) + var totalMainAxisGroups = 1 + var currentAccumulated = 0 + spans.forEach { span -> + if (currentAccumulated + span <= primarySpaces) { + currentAccumulated += span + } else { + totalMainAxisGroups += 1 + currentAccumulated = span + } + } val crossAxisSize = if (isVertical) constraints.maxWidth else constraints.maxHeight check(crossAxisSize != Constraints.Infinity) { "Width must be constrained" } if (slotPositionsAndSizesCache.sizes.size != primarySpaces) { @@ -275,11 +280,54 @@ private fun SpannedGrid( } placeable.placeRelative(x, y) } + state.onPlaceResults(placeables) } } } -fun makeConstraint(isVertical: Boolean, mainAxisSize: Int, crossAxisSize: Int): Constraints { +/** Receiver scope which is used by [VerticalSpannedGrid] and [HorizontalSpannedGrid] */ +@Stable +object SpannedGridScope { + fun Modifier.span(span: Int) = this then SpanElement(span) +} + +/** A state object that can be hoisted to observe items positioning */ +@Stable +sealed interface SpannedGridState { + data class Position(val row: Int, val column: Int) + + val positions: List<Position> +} + +private class SpannedGridStateImpl : SpannedGridState { + private val _positions = mutableStateListOf<SpannedGridState.Position>() + override val positions + get() = _positions + + private var isVertical by mutableStateOf(false) + + fun onPlaceResults(placeResults: List<PlaceResult>) { + _positions.clear() + _positions.addAll( + placeResults.fastMap { placeResult -> + SpannedGridState.Position( + row = if (isVertical) placeResult.mainAxisGroup else placeResult.slotIndex, + column = if (isVertical) placeResult.slotIndex else placeResult.mainAxisGroup, + ) + } + ) + } + + fun setOrientation(isVertical: Boolean) { + this.isVertical = isVertical + } +} + +private fun makeConstraint( + isVertical: Boolean, + mainAxisSize: Int, + crossAxisSize: Int, +): Constraints { return if (isVertical) { Constraints(maxHeight = mainAxisSize, minWidth = crossAxisSize, maxWidth = crossAxisSize) } else { @@ -319,3 +367,27 @@ private data class PlaceResult( val slotIndex: Int, val mainAxisGroup: Int, ) + +private val IntrinsicMeasurable.spannedGridParentData: SpannedGridParentData? + get() = parentData as? SpannedGridParentData + +private val SpannedGridParentData?.span: Int + get() = this?.span ?: 1 + +private data class SpannedGridParentData(val span: Int = 1) + +private data class SpanElement(val span: Int) : ModifierNodeElement<SpanNode>() { + override fun create(): SpanNode { + return SpanNode(span) + } + + override fun update(node: SpanNode) { + node.span = span + } +} + +private class SpanNode(var span: Int) : ParentDataModifierNode, Modifier.Node() { + override fun Density.modifyParentData(parentData: Any?): Any? { + return ((parentData as? SpannedGridParentData) ?: SpannedGridParentData()).copy(span = span) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt index 316964a47753..84c4bdf1621a 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.haptics.msdl.qs import android.service.quicksettings.Tile import com.android.systemui.Flags import com.android.systemui.animation.Expandable +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.util.kotlin.pairwise @@ -173,6 +174,7 @@ constructor( } } +@SysUISingleton class TileHapticsViewModelFactoryProvider @Inject constructor(private val tileHapticsViewModelFactory: TileHapticsViewModel.Factory) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index f549e64ca853..d0065c8b06c6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -39,7 +39,6 @@ import androidx.annotation.VisibleForTesting import androidx.core.math.MathUtils import com.android.app.animation.Interpolators import com.android.internal.R -import com.android.keyguard.KeyguardClockSwitchController import com.android.keyguard.KeyguardViewController import com.android.systemui.Flags.fasterUnlockTransition import com.android.systemui.dagger.SysUISingleton @@ -206,7 +205,7 @@ constructor( fun onUnlockAnimationFinished() {} } - /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */ + /** The SmartSpace view on the lockscreen. */ var lockscreenSmartspace: View? = null /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 9f131607cb99..63ac5094c400 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -4058,7 +4058,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { - mRunner = mActivityTransitionAnimator.get().createRunner(mActivityLaunchController); + mRunner = mActivityTransitionAnimator.get() + .createEphemeralRunner(mActivityLaunchController); mRunner.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt index 4bac8f7a1b47..a1fb1a7bb113 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt @@ -110,7 +110,7 @@ constructor( apps: Array<RemoteAnimationTarget>, wallpapers: Array<RemoteAnimationTarget>, nonApps: Array<RemoteAnimationTarget>, - finishedCallback: IRemoteAnimationFinishedCallback? + finishedCallback: IRemoteAnimationFinishedCallback?, ) { Log.d(TAG, "occludeAnimationRunner#onAnimationStart") // Wrap the callback so that it's guaranteed to be nulled out once called. @@ -126,7 +126,7 @@ constructor( taskInfo = apps.firstOrNull()?.taskInfo, ) activityTransitionAnimator - .createRunner(occludeAnimationController) + .createEphemeralRunner(occludeAnimationController) .onAnimationStart( transit, apps, @@ -161,7 +161,7 @@ constructor( apps: Array<RemoteAnimationTarget>, wallpapers: Array<RemoteAnimationTarget>, nonApps: Array<RemoteAnimationTarget>, - finishedCallback: IRemoteAnimationFinishedCallback? + finishedCallback: IRemoteAnimationFinishedCallback?, ) { Log.d(TAG, "unoccludeAnimationRunner#onAnimationStart") // Wrap the callback so that it's guaranteed to be nulled out once called. @@ -179,14 +179,14 @@ constructor( interactionJankMonitor.begin( createInteractionJankMonitorConf( InteractionJankMonitor.CUJ_LOCKSCREEN_OCCLUSION, - "UNOCCLUDE" + "UNOCCLUDE", ) ) if (apps.isEmpty()) { Log.d( TAG, "No apps provided to unocclude runner; " + - "skipping animation and unoccluding." + "skipping animation and unoccluding.", ) unoccludeAnimationFinishedCallback?.onAnimationFinished() return @@ -210,7 +210,7 @@ constructor( 0f, (1f - animatedValue) * surfaceHeight * - UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT + UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT, ) SurfaceParams.Builder(target.leash) @@ -313,12 +313,12 @@ constructor( private fun createInteractionJankMonitorConf( cuj: Int, - tag: String? + tag: String?, ): InteractionJankMonitor.Configuration.Builder { val builder = InteractionJankMonitor.Configuration.Builder.withView( cuj, - keyguardViewController.get().getViewRootImpl().view + keyguardViewController.get().getViewRootImpl().view, ) return if (tag != null) builder.setTag(tag) else builder } 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 4370abf9ce5a..496c6fb96b39 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -33,7 +33,6 @@ import com.android.keyguard.dagger.KeyguardDisplayModule; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; -import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.CoreStartable; import com.android.systemui.animation.ActivityTransitionAnimator; @@ -108,8 +107,7 @@ import java.util.concurrent.Executor; @Module(subcomponents = { KeyguardQsUserSwitchComponent.class, KeyguardStatusBarViewComponent.class, - KeyguardStatusViewComponent.class, - KeyguardUserSwitcherComponent.class}, + KeyguardStatusViewComponent.class}, includes = { DeviceEntryIconTransitionModule.class, FalsingModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt index 74ee052f12b9..57f06fbd3bb5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt @@ -21,13 +21,13 @@ import android.app.StatusBarManager import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.PackageManager -import com.android.systemui.res.R import com.android.systemui.animation.Expandable import com.android.systemui.camera.CameraGestureHelper import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.shade.ShadeDisplayAware import dagger.Lazy @@ -65,7 +65,7 @@ constructor( icon = Icon.Resource( R.drawable.ic_camera, - ContentDescription.Resource(R.string.accessibility_camera_button) + ContentDescription.Resource(R.string.accessibility_camera_button), ) ) } else { @@ -88,7 +88,7 @@ constructor( cameraGestureHelper .get() .launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE) - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true) } private suspend fun isLaunchable(): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt index e8d3bfac6361..1b8baf657948 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt @@ -210,16 +210,16 @@ constructor( ): KeyguardQuickAffordanceConfig.OnTriggeredResult { return if (ModesUi.isEnabled) { if (!isAvailable.value) { - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } else { val dnd = interactor.dndMode.value if (dnd == null) { Log.wtf(TAG, "Triggered DND but it's null!?") - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } if (dnd.isActive) { interactor.deactivateMode(dnd) - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } else { if (interactor.shouldAskForZenDuration(dnd)) { // NOTE: The dialog handles turning on the mode itself. @@ -229,16 +229,16 @@ constructor( ) } else { interactor.activateMode(dnd) - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } } } } else { when { - !oldIsAvailable -> KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + !oldIsAvailable -> KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) zenMode != ZEN_MODE_OFF -> { controller.setZen(ZEN_MODE_OFF, null, TAG) - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } settingsValue == ZEN_DURATION_PROMPT -> @@ -249,12 +249,12 @@ constructor( settingsValue == ZEN_DURATION_FOREVER -> { controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG) - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } else -> { controller.setZen(ZEN_MODE_IMPORTANT_INTERRUPTIONS, conditionUri, TAG) - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt index 480ef5e19d8e..e2642a0964c1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt @@ -18,15 +18,14 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Context -import com.android.systemui.res.R import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.shared.quickaffordance.ActivationState +import com.android.systemui.res.R import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.statusbar.policy.FlashlightController import javax.inject.Inject @@ -50,9 +49,9 @@ constructor( KeyguardQuickAffordanceConfig.LockScreenState.Visible( Icon.Resource( R.drawable.qs_flashlight_icon_on, - ContentDescription.Resource(R.string.quick_settings_flashlight_label) + ContentDescription.Resource(R.string.quick_settings_flashlight_label), ), - ActivationState.Active + ActivationState.Active, ) } @@ -61,9 +60,9 @@ constructor( KeyguardQuickAffordanceConfig.LockScreenState.Visible( Icon.Resource( R.drawable.qs_flashlight_icon_off, - ContentDescription.Resource(R.string.quick_settings_flashlight_label) + ContentDescription.Resource(R.string.quick_settings_flashlight_label), ), - ActivationState.Inactive + ActivationState.Inactive, ) } @@ -92,14 +91,14 @@ constructor( } else { FlashlightState.OffAvailable.toLockScreenState() }, - TAG + TAG, ) } override fun onFlashlightError() { trySendWithFailureLogging( FlashlightState.OffAvailable.toLockScreenState(), - TAG + TAG, ) } @@ -114,7 +113,7 @@ constructor( FlashlightState.OffAvailable.toLockScreenState() } }, - TAG + TAG, ) } } @@ -130,7 +129,7 @@ constructor( flashlightController.setFlashlight( flashlightController.isAvailable && !flashlightController.isEnabled ) - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt index d335a1806a6d..96b07cc84705 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt @@ -36,7 +36,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map /** Lockscreen affordance that opens the glanceable hub. */ @SysUISingleton @@ -60,13 +60,13 @@ constructor( get() = R.drawable.ic_widgets override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> - get() = flow { - emit( + get() = + communalInteractor.isCommunalAvailable.map { available -> if (!communalSettingsInteractor.isV2FlagEnabled()) { Log.i(TAG, "Button hidden on lockscreen: flag not enabled.") KeyguardQuickAffordanceConfig.LockScreenState.Hidden - } else if (!communalInteractor.isCommunalEnabled.value) { - Log.i(TAG, "Button hidden on lockscreen: hub not enabled in settings.") + } else if (!available) { + Log.i(TAG, "Button hidden on lockscreen: hub not available.") KeyguardQuickAffordanceConfig.LockScreenState.Hidden } else { KeyguardQuickAffordanceConfig.LockScreenState.Visible( @@ -77,8 +77,7 @@ constructor( ) ) } - ) - } + } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { return if (!communalSettingsInteractor.isV2FlagEnabled()) { @@ -111,7 +110,7 @@ constructor( transitionKey = CommunalTransitionKeys.SimpleFade, ) } - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true) } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt index 1cf6183fec6c..ade65c38ff3c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt @@ -21,10 +21,10 @@ import android.app.AlertDialog import android.content.Context import android.content.Intent import android.net.Uri -import com.android.systemui.res.R import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon import com.android.systemui.keyguard.shared.quickaffordance.ActivationState +import com.android.systemui.res.R import kotlinx.coroutines.flow.Flow /** Defines interface that can act as data source for a single quick affordance model. */ @@ -71,7 +71,7 @@ interface KeyguardQuickAffordanceConfig { /** The picker shows the item for selecting this affordance as it normally would. */ data class Default( /** Optional [Intent] to use to start an activity to configure this affordance. */ - val configureIntent: Intent? = null, + val configureIntent: Intent? = null ) : PickerScreenState() /** @@ -134,34 +134,39 @@ interface KeyguardQuickAffordanceConfig { ) : LockScreenState() } - sealed class OnTriggeredResult { + sealed class OnTriggeredResult() { /** * Returning this as a result from the [onTriggered] method means that the implementation * has taken care of the action, the system will do nothing. + * + * @param[actionLaunched] Whether the implementation handled the action by launching a + * dialog or an activity. */ - object Handled : OnTriggeredResult() + data class Handled(val actionLaunched: Boolean) : OnTriggeredResult() /** * Returning this as a result from the [onTriggered] method means that the implementation * has _not_ taken care of the action and the system should start an activity using the * given [Intent]. */ - data class StartActivity( - val intent: Intent, - val canShowWhileLocked: Boolean, - ) : OnTriggeredResult() + data class StartActivity(val intent: Intent, val canShowWhileLocked: Boolean) : + OnTriggeredResult() /** * Returning this as a result from the [onTriggered] method means that the implementation * has _not_ taken care of the action and the system should show a Dialog using the given * [AlertDialog] and [Expandable]. */ - data class ShowDialog( - val dialog: AlertDialog, - val expandable: Expandable?, - ) : OnTriggeredResult() + data class ShowDialog(val dialog: AlertDialog, val expandable: Expandable?) : + OnTriggeredResult() } + /** + * Models an [OnTriggeredResult] that did or did not launch a dialog or activity for a given + * config key. + */ + data class LaunchingFromTriggeredResult(val launched: Boolean, val configKey: String) + companion object { /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt index f08576abc44f..c7749876c683 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt @@ -24,8 +24,8 @@ import com.android.systemui.backup.BackupHelper import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.res.R import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker @@ -51,6 +51,7 @@ constructor( @ShadeDisplayAware private val context: Context, private val userFileManager: UserFileManager, private val userTracker: UserTracker, + private val communalSettingsInteractor: CommunalSettingsInteractor, broadcastDispatcher: BroadcastDispatcher, ) : KeyguardQuickAffordanceSelectionManager { @@ -102,7 +103,7 @@ constructor( // common case anyway as restoration really only happens on initial device // setup). emit(Unit) - } + }, ) { _, _ -> } .flatMapLatest { @@ -128,7 +129,11 @@ constructor( override fun getSelections(): Map<String, List<String>> { // If the custom shortcuts feature is not enabled, ignore prior selections and use defaults - if (!context.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled)) { + // TODO(b/383391342): remove isV2FlagEnabled check and just depend on the resource + if ( + !(context.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled) || + communalSettingsInteractor.isV2FlagEnabled()) + ) { return defaults } @@ -164,10 +169,7 @@ constructor( return result } - override fun setSelections( - slotId: String, - affordanceIds: List<String>, - ) { + override fun setSelections(slotId: String, affordanceIds: List<String>) { val key = "$KEY_PREFIX_SLOT$slotId" val value = affordanceIds.joinToString(AFFORDANCE_DELIMITER) sharedPrefs.edit().putString(key, value).apply() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt index 1358634a55f8..1c9bc9f39663 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt @@ -21,6 +21,7 @@ import android.content.Context import android.media.AudioManager import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.animation.Expandable import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.shared.model.ContentDescription @@ -45,7 +46,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext @SysUISingleton @@ -118,7 +118,7 @@ constructor( audioManager.ringerModeInternal = newRingerMode } } - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState = @@ -140,11 +140,11 @@ constructor( .getSharedPreferences( MUTE_QUICK_AFFORDANCE_PREFS_FILE_NAME, Context.MODE_PRIVATE, - userTracker.userId + userTracker.userId, ) .getInt( LAST_NON_SILENT_RINGER_MODE_KEY, - ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE + ringerModeTracker.ringerModeInternal.value ?: DEFAULT_LAST_NON_SILENT_VALUE, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt index eafa1cea59f3..cb7702e090d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt @@ -30,7 +30,6 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R @@ -72,21 +71,15 @@ constructor( override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) { val hasCards = getPaymentCards(response.walletCards)?.isNotEmpty() == true - trySendWithFailureLogging( - hasCards, - TAG, - ) + trySendWithFailureLogging(hasCards, TAG) } override fun onWalletCardRetrievalError(error: GetWalletCardsError) { Log.e( TAG, - "Wallet card retrieval error, message: \"${error?.message}\"" - ) - trySendWithFailureLogging( - null, - TAG, + "Wallet card retrieval error, message: \"${error?.message}\"", ) + trySendWithFailureLogging(null, TAG) } } @@ -94,7 +87,7 @@ constructor( callback, QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE, QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE, - QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE + QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE, ) withContext(backgroundDispatcher) { @@ -107,7 +100,7 @@ constructor( walletController.unregisterWalletChangeObservers( QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE, QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE, - QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE + QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE, ) } } @@ -117,11 +110,7 @@ constructor( if (hasCards == null) { KeyguardQuickAffordanceConfig.LockScreenState.Hidden } else { - state( - isWalletAvailable(), - hasCards, - walletController.walletClient.tileIcon, - ) + state(isWalletAvailable(), hasCards, walletController.walletClient.tileIcon) } flowOf(state) } @@ -135,28 +124,28 @@ constructor( explanation = context.getString( R.string.wallet_quick_affordance_unavailable_install_the_app - ), + ) ) queryCards().isEmpty() -> KeyguardQuickAffordanceConfig.PickerScreenState.Disabled( explanation = context.getString( R.string.wallet_quick_affordance_unavailable_configure_the_app - ), + ) ) else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default() } } override fun onTriggered( - expandable: Expandable?, + expandable: Expandable? ): KeyguardQuickAffordanceConfig.OnTriggeredResult { walletController.startQuickAccessUiIntent( activityStarter, expandable?.activityTransitionController(), /* hasCard= */ true, ) - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true) } private suspend fun queryCards(): List<WalletCard> { @@ -199,10 +188,8 @@ constructor( Icon.Loaded( drawable = tileIcon, contentDescription = - ContentDescription.Resource( - res = R.string.accessibility_wallet_button, - ), - ), + ContentDescription.Resource(res = R.string.accessibility_wallet_button), + ) ) } else { KeyguardQuickAffordanceConfig.LockScreenState.Hidden 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 ae55825c9842..7d8badd232b9 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 @@ -28,8 +28,8 @@ import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled import com.android.systemui.dock.DockManager @@ -62,6 +62,7 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine @@ -90,6 +91,7 @@ constructor( private val devicePolicyManager: DevicePolicyManager, private val dockManager: DockManager, private val biometricSettingsRepository: BiometricSettingsRepository, + private val communalSettingsInteractor: CommunalSettingsInteractor, @Background private val backgroundDispatcher: CoroutineDispatcher, @ShadeDisplayAware private val appContext: Context, private val sceneInteractor: Lazy<SceneInteractor>, @@ -101,6 +103,14 @@ constructor( val launchingAffordance: StateFlow<Boolean> = repository.get().launchingAffordance.asStateFlow() /** + * Whether a [KeyguardQuickAffordanceConfig.OnTriggeredResult] indicated that the system + * launched an activity or showed a dialog. + */ + private val _launchingFromTriggeredResult = + MutableStateFlow<KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult?>(null) + val launchingFromTriggeredResult = _launchingFromTriggeredResult.asStateFlow() + + /** * Whether the UI should use the long press gesture to activate quick affordances. * * If `false`, the UI goes back to using single taps. @@ -187,18 +197,45 @@ constructor( metricsLogger.logOnShortcutTriggered(slotId, configKey) when (val result = config.onTriggered(expandable)) { - is KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity -> + is KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity -> { + setLaunchingFromTriggeredResult( + KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult( + launched = true, + configKey, + ) + ) launchQuickAffordance( intent = result.intent, canShowWhileLocked = result.canShowWhileLocked, expandable = expandable, ) - is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> Unit - is KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog -> + } + is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> { + setLaunchingFromTriggeredResult( + KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult( + result.actionLaunched, + configKey, + ) + ) + } + is KeyguardQuickAffordanceConfig.OnTriggeredResult.ShowDialog -> { + setLaunchingFromTriggeredResult( + KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult( + launched = true, + configKey, + ) + ) showDialog(result.dialog, result.expandable) + } } } + fun setLaunchingFromTriggeredResult( + launchingResult: KeyguardQuickAffordanceConfig.LaunchingFromTriggeredResult? + ) { + _launchingFromTriggeredResult.value = launchingResult + } + /** * Selects an affordance with the given ID on the slot with the given ID. * @@ -427,7 +464,10 @@ constructor( name = Contract.FlagsTable.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED, value = !isFeatureDisabledByDevicePolicy() && - appContext.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled), + // TODO(b/383391342): remove isV2FlagEnabled check once trunkfood is reached + (appContext.resources.getBoolean( + R.bool.custom_lockscreen_shortcuts_enabled + ) || communalSettingsInteractor.isV2FlagEnabled()), ), KeyguardPickerFlag( name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt index aa44b6d46289..382436cf9397 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor.scenetransition +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.systemui.CoreStartable @@ -38,7 +39,6 @@ import java.util.UUID import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import com.android.app.tracing.coroutines.launchTraced as launch /** * This class listens to scene framework scene transitions and manages keyguard transition framework @@ -111,7 +111,10 @@ constructor( if (currentTransitionId == null) return if (prevTransition !is ObservableTransitionState.Transition) return - if (idle.currentScene == prevTransition.toContent) { + if ( + idle.currentScene == prevTransition.toContent || + idle.currentOverlays.contains(prevTransition.toContent) + ) { finishCurrentTransition() } else { val targetState = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt index e7803c5e964c..a4a5ba691965 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaVibrations.kt @@ -17,12 +17,23 @@ package com.android.systemui.keyguard.ui.binder import android.os.VibrationEffect +import com.android.systemui.Flags import kotlin.time.Duration.Companion.milliseconds object KeyguardBottomAreaVibrations { - val ShakeAnimationDuration = 300.milliseconds - const val ShakeAnimationCycles = 5f + val ShakeAnimationDuration = + if (Flags.msdlFeedback()) { + 285.milliseconds + } else { + 300.milliseconds + } + val ShakeAnimationCycles = + if (Flags.msdlFeedback()) { + 3f + } else { + 5f + } private const val SmallVibrationScale = 0.3f private const val BigVibrationScale = 0.6f @@ -32,7 +43,7 @@ object KeyguardBottomAreaVibrations { .apply { val vibrationDelayMs = (ShakeAnimationDuration.inWholeMilliseconds / (ShakeAnimationCycles * 2)) - .toInt() + .toInt() val vibrationCount = ShakeAnimationCycles.toInt() * 2 repeat(vibrationCount) { @@ -47,29 +58,13 @@ object KeyguardBottomAreaVibrations { val Activated = VibrationEffect.startComposition() - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, - BigVibrationScale, - 0, - ) - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, - 0.1f, - 0, - ) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, BigVibrationScale, 0) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 0.1f, 0) .compose() val Deactivated = VibrationEffect.startComposition() - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, - BigVibrationScale, - 0, - ) - .addPrimitive( - VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, - 0.1f, - 0, - ) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, BigVibrationScale, 0) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, 0.1f, 0) .compose() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt index 8725cdd273df..8a2e3dd791c2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.ui.binder import android.annotation.SuppressLint import android.content.res.ColorStateList import android.graphics.drawable.Animatable2 +import android.os.VibrationEffect import android.util.Size import android.view.View import android.view.ViewGroup @@ -33,25 +34,27 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.logging.KeyguardQuickAffordancesLogger +import com.android.systemui.Flags import com.android.systemui.animation.Expandable import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceHapticViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.util.doOnEnd +import com.google.android.msdl.data.model.MSDLToken +import com.google.android.msdl.domain.MSDLPlayer import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map -import com.android.app.tracing.coroutines.launchTraced as launch /** This is only for a SINGLE Quick affordance */ @SysUISingleton @@ -60,8 +63,9 @@ class KeyguardQuickAffordanceViewBinder constructor( private val falsingManager: FalsingManager?, private val vibratorHelper: VibratorHelper?, + private val msdlPlayer: MSDLPlayer, private val logger: KeyguardQuickAffordancesLogger, - @Main private val mainImmediateDispatcher: CoroutineDispatcher, + private val hapticsViewModelFactory: KeyguardQuickAffordanceHapticViewModel.Factory, ) { private val EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS = 250L @@ -88,6 +92,12 @@ constructor( ): Binding { val button = view as ImageView val configurationBasedDimensions = MutableStateFlow(loadFromResources(view)) + val hapticsViewModel = + if (Flags.msdlFeedback()) { + hapticsViewModelFactory.create(viewModel) + } else { + null + } val disposableHandle = view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { @@ -98,15 +108,12 @@ constructor( viewModel = buttonModel, messageDisplayer = messageDisplayer, ) + hapticsViewModel?.updateActivatedHistory(buttonModel.isActivated) } } launch { - updateButtonAlpha( - view = button, - viewModel = viewModel, - alphaFlow = alpha, - ) + updateButtonAlpha(view = button, viewModel = viewModel, alphaFlow = alpha) } launch { @@ -117,6 +124,32 @@ constructor( } } } + + if (Flags.msdlFeedback()) { + launch { + hapticsViewModel + ?.quickAffordanceHapticState + ?.filter { + it != + KeyguardQuickAffordanceHapticViewModel.HapticState + .NO_HAPTICS + } + ?.collect { state -> + when (state) { + KeyguardQuickAffordanceHapticViewModel.HapticState + .TOGGLE_ON -> msdlPlayer.playToken(MSDLToken.SWITCH_ON) + KeyguardQuickAffordanceHapticViewModel.HapticState + .TOGGLE_OFF -> + msdlPlayer.playToken(MSDLToken.SWITCH_OFF) + KeyguardQuickAffordanceHapticViewModel.HapticState.LAUNCH -> + msdlPlayer.playToken(MSDLToken.LONG_PRESS) + KeyguardQuickAffordanceHapticViewModel.HapticState + .NO_HAPTICS -> Unit + } + hapticsViewModel.resetLaunchingFromTriggeredResult() + } + } + } } } @@ -178,7 +211,7 @@ constructor( com.android.internal.R.color.materialColorOnPrimaryFixed } else { com.android.internal.R.color.materialColorOnSurface - }, + } ) ) @@ -221,12 +254,7 @@ constructor( .getDimensionPixelSize(R.dimen.keyguard_affordance_shake_amplitude) .toFloat() val shakeAnimator = - ObjectAnimator.ofFloat( - view, - "translationX", - -amplitude / 2, - amplitude / 2, - ) + ObjectAnimator.ofFloat(view, "translationX", -amplitude / 2, amplitude / 2) shakeAnimator.duration = KeyguardBottomAreaVibrations.ShakeAnimationDuration.inWholeMilliseconds shakeAnimator.interpolator = @@ -234,11 +262,17 @@ constructor( shakeAnimator.doOnEnd { view.translationX = 0f } shakeAnimator.start() - vibratorHelper?.vibrate(KeyguardBottomAreaVibrations.Shake) + vibratorHelper?.playFeedback(KeyguardBottomAreaVibrations.Shake, msdlPlayer) logger.logQuickAffordanceTapped(viewModel.configKey) } view.onLongClickListener = - OnLongClickListener(falsingManager, viewModel, vibratorHelper, onTouchListener) + OnLongClickListener( + falsingManager, + viewModel, + vibratorHelper, + onTouchListener, + msdlPlayer, + ) } else { view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager))) } @@ -268,7 +302,7 @@ constructor( Size( view.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width), view.resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height), - ), + ) ) } @@ -297,7 +331,8 @@ constructor( private val falsingManager: FalsingManager?, private val viewModel: KeyguardQuickAffordanceViewModel, private val vibratorHelper: VibratorHelper?, - private val onTouchListener: KeyguardQuickAffordanceOnTouchListener + private val onTouchListener: KeyguardQuickAffordanceOnTouchListener, + private val msdlPlayer: MSDLPlayer, ) : View.OnLongClickListener { override fun onLongClick(view: View): Boolean { if (falsingManager?.isFalseLongTap(FalsingManager.MODERATE_PENALTY) == true) { @@ -312,12 +347,13 @@ constructor( slotId = viewModel.slotId, ) ) - vibratorHelper?.vibrate( + vibratorHelper?.playFeedback( if (viewModel.isActivated) { KeyguardBottomAreaVibrations.Activated } else { KeyguardBottomAreaVibrations.Deactivated - } + }, + msdlPlayer, ) } @@ -328,7 +364,15 @@ constructor( override fun onLongClickUseDefaultHapticFeedback(view: View) = false } - private data class ConfigurationBasedDimensions( - val buttonSizePx: Size, - ) + private data class ConfigurationBasedDimensions(val buttonSizePx: Size) +} + +private fun VibratorHelper.playFeedback(effect: VibrationEffect, msdlPlayer: MSDLPlayer) { + if (!Flags.msdlFeedback()) { + vibrate(effect) + } else { + if (effect == KeyguardBottomAreaVibrations.Shake) { + msdlPlayer.playToken(MSDLToken.FAILURE) + } + } } 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 a2ce4ec5ce9b..6d270b219c81 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 @@ -127,21 +127,18 @@ object KeyguardRootViewBinder { if (Flags.nonTouchscreenDevicesBypassFalsing()) { if ( event.action == MotionEvent.ACTION_DOWN && - event.buttonState == MotionEvent.BUTTON_PRIMARY && - !event.isTouchscreenSource() + event.buttonState == MotionEvent.BUTTON_PRIMARY && + !event.isTouchscreenSource() ) { consumed = true } else if ( - event.action == MotionEvent.ACTION_UP && - !event.isTouchscreenSource() + event.action == MotionEvent.ACTION_UP && !event.isTouchscreenSource() ) { statusBarKeyguardViewManager?.showBouncer(true) consumed = true } } - viewModel.setRootViewLastTapPosition( - Point(event.x.toInt(), event.y.toInt()) - ) + viewModel.setRootViewLastTapPosition(Point(event.x.toInt(), event.y.toInt())) } consumed } @@ -172,7 +169,6 @@ object KeyguardRootViewBinder { launch("$TAG#alpha") { viewModel.alpha(viewState).collect { alpha -> view.alpha = alpha - childViews[statusViewId]?.alpha = alpha childViews[burnInLayerId]?.alpha = alpha } } @@ -253,18 +249,6 @@ object KeyguardRootViewBinder { } launch { - viewModel.burnInLayerAlpha.collect { alpha -> - childViews[statusViewId]?.alpha = alpha - } - } - - launch { - viewModel.lockscreenStateAlpha(viewState).collect { alpha -> - childViews[statusViewId]?.alpha = alpha - } - } - - launch { viewModel.scale.collect { scaleViewModel -> if (scaleViewModel.scaleClockOnly) { // For clocks except weather clock, we have scale transition besides @@ -553,7 +537,6 @@ object KeyguardRootViewBinder { return device?.supportsSource(InputDevice.SOURCE_TOUCHSCREEN) == true } - private val statusViewId = R.id.keyguard_status_view private val burnInLayerId = R.id.burn_in_layer private val aodNotificationIconContainerId = R.id.aod_notification_icon_container private val largeClockId = customR.id.lockscreen_clock_view_large diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index 090b65922d2d..6fb31c0e4191 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -48,19 +48,16 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.core.view.isInvisible -import com.android.internal.policy.SystemBarUtils import com.android.keyguard.ClockEventController -import com.android.keyguard.KeyguardClockSwitch import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel -import com.android.systemui.coroutines.newTracingContext +import com.android.systemui.customization.R as customR import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.shared.model.ClockSizeSetting import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder @@ -80,7 +77,6 @@ import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shared.clocks.ClockRegistry -import com.android.systemui.shared.clocks.DefaultClockController import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants @@ -91,18 +87,13 @@ import com.android.systemui.util.settings.SecureSettings import dagger.assisted.Assisted import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.json.JSONException import org.json.JSONObject -import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.customization.R as customR /** Renders the preview of the lock screen. */ class KeyguardPreviewRenderer @@ -110,7 +101,6 @@ class KeyguardPreviewRenderer @AssistedInject constructor( @Application private val context: Context, - @Application applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, @Main private val mainHandler: Handler, @Background private val backgroundDispatcher: CoroutineDispatcher, @@ -157,8 +147,6 @@ constructor( val surfacePackage: SurfaceControlViewHost.SurfacePackage get() = checkNotNull(host.surfacePackage) - private lateinit var largeClockHostView: FrameLayout - private lateinit var smallClockHostView: FrameLayout private var smartSpaceView: View? = null private val disposables = DisposableHandles() @@ -166,29 +154,18 @@ constructor( private val shortcutsBindings = mutableSetOf<KeyguardQuickAffordanceViewBinder.Binding>() - private val coroutineScope: CoroutineScope - @Style.Type private var themeStyle: Int? = null init { - coroutineScope = - CoroutineScope( - applicationScope.coroutineContext + - Job() + - newTracingContext("KeyguardPreviewRenderer") - ) - disposables += DisposableHandle { coroutineScope.cancel() } clockController.setFallbackWeatherData(WeatherData.getPlaceholderWeatherData()) - quickAffordancesCombinedViewModel.enablePreviewMode( initiallySelectedSlotId = - bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID) - ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, + bundle.getString(KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID) + ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance, ) - if (MigrateClocksToBlueprint.isEnabled) { - clockViewModel.shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance - } + + clockViewModel.shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance runBlocking(mainDispatcher) { host = SurfaceControlViewHost( @@ -348,6 +325,7 @@ constructor( smartSpaceView?.alpha = if (shouldHighlightSelectedAffordance) DIM_ALPHA else 1.0f } + @OptIn(ExperimentalCoroutinesApi::class) private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) { val keyguardRootView = KeyguardRootView(previewContext, null) rootView.addView( @@ -358,34 +336,23 @@ constructor( ), ) - setUpUdfps( - previewContext, - if (MigrateClocksToBlueprint.isEnabled) keyguardRootView else rootView, - ) + setUpUdfps(previewContext, keyguardRootView) setupShortcuts(keyguardRootView) if (!shouldHideClock) { setUpClock(previewContext, rootView) - if (MigrateClocksToBlueprint.isEnabled) { - KeyguardPreviewClockViewBinder.bind( - keyguardRootView, - clockViewModel, - clockRegistry, - ::updateClockAppearance, - ClockPreviewConfig( - previewContext, - getPreviewShadeLayoutWide(display!!), - SceneContainerFlag.isEnabled, - ), - ) - } else { - KeyguardPreviewClockViewBinder.bind( - largeClockHostView, - smallClockHostView, - clockViewModel, - ) - } + KeyguardPreviewClockViewBinder.bind( + keyguardRootView, + clockViewModel, + clockRegistry, + ::updateClockAppearance, + ClockPreviewConfig( + previewContext, + getPreviewShadeLayoutWide(display!!), + SceneContainerFlag.isEnabled, + ), + ) } setUpSmartspace(previewContext, rootView) @@ -451,82 +418,22 @@ constructor( .inflate(R.layout.udfps_keyguard_preview, parentView, false) as View // Place the UDFPS view in the proper sensor location - if (MigrateClocksToBlueprint.isEnabled) { - val lockId = KeyguardPreviewClockViewBinder.lockId - finger.id = lockId - parentView.addView(finger) - val cs = ConstraintSet() - cs.clone(parentView as ConstraintLayout) - cs.apply { - constrainWidth(lockId, sensorBounds.width()) - constrainHeight(lockId, sensorBounds.height()) - connect(lockId, TOP, PARENT_ID, TOP, sensorBounds.top) - connect(lockId, START, PARENT_ID, START, sensorBounds.left) - } - cs.applyTo(parentView) - } else { - val fingerprintLayoutParams = - FrameLayout.LayoutParams(sensorBounds.width(), sensorBounds.height()) - fingerprintLayoutParams.setMarginsRelative( - sensorBounds.left, - sensorBounds.top, - sensorBounds.right, - sensorBounds.bottom, - ) - parentView.addView(finger, fingerprintLayoutParams) + val lockId = KeyguardPreviewClockViewBinder.lockId + finger.id = lockId + parentView.addView(finger) + val cs = ConstraintSet() + cs.clone(parentView as ConstraintLayout) + cs.apply { + constrainWidth(lockId, sensorBounds.width()) + constrainHeight(lockId, sensorBounds.height()) + connect(lockId, TOP, PARENT_ID, TOP, sensorBounds.top) + connect(lockId, START, PARENT_ID, START, sensorBounds.left) } + cs.applyTo(parentView) } private fun setUpClock(previewContext: Context, parentView: ViewGroup) { val resources = parentView.resources - if (!MigrateClocksToBlueprint.isEnabled) { - largeClockHostView = FrameLayout(previewContext) - largeClockHostView.layoutParams = - FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT, - ) - largeClockHostView.isInvisible = true - parentView.addView(largeClockHostView) - - smallClockHostView = FrameLayout(previewContext) - val layoutParams = - FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - resources.getDimensionPixelSize(customR.dimen.small_clock_height), - ) - layoutParams.topMargin = - SystemBarUtils.getStatusBarHeight(previewContext) + - resources.getDimensionPixelSize(customR.dimen.small_clock_padding_top) - smallClockHostView.layoutParams = layoutParams - smallClockHostView.setPaddingRelative( - /* start = */ resources.getDimensionPixelSize(customR.dimen.clock_padding_start), - /* top = */ 0, - /* end = */ 0, - /* bottom = */ 0, - ) - smallClockHostView.clipChildren = false - parentView.addView(smallClockHostView) - smallClockHostView.isInvisible = true - } - - // TODO (b/283465254): Move the listeners to KeyguardClockRepository - if (!MigrateClocksToBlueprint.isEnabled) { - val clockChangeListener = - object : ClockRegistry.ClockChangeListener { - override fun onCurrentClockChanged() { - onClockChanged() - } - } - clockRegistry.registerClockChangeListener(clockChangeListener) - disposables += DisposableHandle { - clockRegistry.unregisterClockChangeListener(clockChangeListener) - } - - clockController.registerListeners(parentView) - disposables += DisposableHandle { clockController.unregisterListeners() } - } - val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -544,38 +451,9 @@ constructor( }, ) disposables += DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) } - - if (!MigrateClocksToBlueprint.isEnabled) { - val layoutChangeListener = - View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> - if (clockController.clock !is DefaultClockController) { - clockController.clock - ?.largeClock - ?.events - ?.onTargetRegionChanged( - KeyguardClockSwitch.getLargeClockRegion(parentView) - ) - clockController.clock - ?.smallClock - ?.events - ?.onTargetRegionChanged( - KeyguardClockSwitch.getSmallClockRegion(parentView) - ) - } - } - parentView.addOnLayoutChangeListener(layoutChangeListener) - disposables += DisposableHandle { - parentView.removeOnLayoutChangeListener(layoutChangeListener) - } - } - - onClockChanged() } private suspend fun updateClockAppearance(clock: ClockController, resources: Resources) { - if (!MigrateClocksToBlueprint.isEnabled) { - clockController.clock = clock - } val colors = wallpaperColors if (clockRegistry.seedColor == null && colors != null) { // Seed color null means users do not override any color on the clock. The default @@ -601,9 +479,7 @@ constructor( // In clock preview, we should have a seed color for clock // before setting clock to clockEventController to avoid updateColor with seedColor == null // So in update colors, it should already have the correct theme in clockFaceController - if (MigrateClocksToBlueprint.isEnabled) { - clockController.clock = clock - } + clockController.clock = clock // When set clock to clockController,it will reset fontsize based on context.resources // We need to override it with overlaid resources clock.largeClock.events.onFontSettingChanged( @@ -611,19 +487,6 @@ constructor( ) } - private fun onClockChanged() { - if (MigrateClocksToBlueprint.isEnabled) { - return - } - coroutineScope.launch { - val clock = clockRegistry.createCurrentClock() - clockController.clock = clock - updateClockAppearance(clock, context.resources) - updateLargeClock(clock) - updateSmallClock(clock) - } - } - private fun setupCommunalTutorialIndicator(keyguardRootView: ConstraintLayout) { keyguardRootView.findViewById<TextView>(R.id.communal_tutorial_indicator)?.let { indicatorView -> @@ -657,34 +520,6 @@ constructor( } } - private fun updateLargeClock(clock: ClockController) { - if (MigrateClocksToBlueprint.isEnabled) { - return - } - clock.largeClock.events.onTargetRegionChanged( - KeyguardClockSwitch.getLargeClockRegion(largeClockHostView) - ) - if (shouldHighlightSelectedAffordance) { - clock.largeClock.view.alpha = DIM_ALPHA - } - largeClockHostView.removeAllViews() - largeClockHostView.addView(clock.largeClock.view) - } - - private fun updateSmallClock(clock: ClockController) { - if (MigrateClocksToBlueprint.isEnabled) { - return - } - clock.smallClock.events.onTargetRegionChanged( - KeyguardClockSwitch.getSmallClockRegion(smallClockHostView) - ) - if (shouldHighlightSelectedAffordance) { - clock.smallClock.view.alpha = DIM_ALPHA - } - smallClockHostView.removeAllViews() - smallClockHostView.addView(clock.smallClock.view) - } - private fun getPreviewShadeLayoutWide(display: Display): Boolean { return if (display.displayId == 0) { shadeInteractor.isShadeLayoutWide.value diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt index 160380bb09bc..57fe15d4f52c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt @@ -24,7 +24,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.BOTTOM import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel @@ -50,9 +49,6 @@ constructor( } override fun addViews(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } if (emptyView.parent != null) { // As emptyView is lazy, it might be already attached. (emptyView.parent as? ViewGroup)?.removeView(emptyView) @@ -68,17 +64,10 @@ constructor( } override fun bindData(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } clockViewModel.burnInLayer = burnInLayer } override fun applyConstraints(constraintSet: ConstraintSet) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } - constraintSet.apply { // The empty view should not occupy any space constrainHeight(R.id.burn_in_layer_empty_view, 1) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index 70bf8bca55b9..738fb73a4918 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -32,7 +32,6 @@ import androidx.constraintlayout.widget.ConstraintSet.VISIBLE import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection @@ -82,9 +81,6 @@ constructor( override fun addViews(constraintLayout: ConstraintLayout) {} override fun bindData(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } disposableHandle?.dispose() disposableHandle = KeyguardClockViewBinder.bind( @@ -99,20 +95,12 @@ constructor( } override fun applyConstraints(constraintSet: ConstraintSet) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } - keyguardClockViewModel.currentClock.value?.let { clock -> constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet)) } } override fun removeViews(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } - disposableHandle?.dispose() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt index 3a791fd45528..4bfe5f0458c5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt @@ -24,7 +24,6 @@ import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.res.R import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.NotificationPanelView @@ -54,32 +53,25 @@ constructor( sharedNotificationContainerBinder, ) { override fun applyConstraints(constraintSet: ConstraintSet) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } constraintSet.apply { val bottomMargin = context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin) - if (MigrateClocksToBlueprint.isEnabled) { - val useLargeScreenHeader = - context.resources.getBoolean(R.bool.config_use_large_screen_shade_header) - val marginTopLargeScreen = - largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() - connect( - R.id.nssl_placeholder, - TOP, - R.id.smart_space_barrier_bottom, - BOTTOM, - bottomMargin + - if (useLargeScreenHeader) { - marginTopLargeScreen - } else { - 0 - } - ) - } else { - connect(R.id.nssl_placeholder, TOP, R.id.keyguard_status_view, BOTTOM, bottomMargin) - } + val useLargeScreenHeader = + context.resources.getBoolean(R.bool.config_use_large_screen_shade_header) + val marginTopLargeScreen = + largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + connect( + R.id.nssl_placeholder, + TOP, + R.id.smart_space_barrier_bottom, + BOTTOM, + bottomMargin + + if (useLargeScreenHeader) { + marginTopLargeScreen + } else { + 0 + }, + ) connect(R.id.nssl_placeholder, START, PARENT_ID, START) connect(R.id.nssl_placeholder, END, PARENT_ID, END) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt index 620cc13a0c3a..fc26d18fde6b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt @@ -25,7 +25,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet.BOTTOM import androidx.constraintlayout.widget.ConstraintSet.TOP -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.res.R import com.android.systemui.shade.NotificationPanelView @@ -62,9 +61,6 @@ constructor( } override fun addViews(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } // This moves the existing NSSL view to a different parent, as the controller is a // singleton and recreating it has other bad side effects. // In the SceneContainer, this is done by the NotificationSection composable. @@ -78,10 +74,6 @@ constructor( } override fun bindData(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } - disposableHandle?.dispose() disposableHandle = sharedNotificationContainerBinder.bind( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 73e14b1524f3..cd038d799f42 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -26,7 +26,6 @@ import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardUnlockAnimationController -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection @@ -70,7 +69,6 @@ constructor( } override fun addViews(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return smartspaceView = smartspaceController.buildAndConnectView(constraintLayout) weatherView = smartspaceController.buildAndConnectWeatherView(constraintLayout) @@ -98,7 +96,6 @@ constructor( } override fun bindData(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return disposableHandle?.dispose() disposableHandle = @@ -111,13 +108,11 @@ constructor( } override fun applyConstraints(constraintSet: ConstraintSet) { - if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return val dateWeatherPaddingStart = KeyguardSmartspaceViewModel.getDateWeatherStartMargin(context) val smartspaceHorizontalPadding = KeyguardSmartspaceViewModel.getSmartspaceHorizontalMargin(context) constraintSet.apply { - // migrate addDateWeatherView, addWeatherView from KeyguardClockSwitchController constrainHeight(sharedR.id.date_smartspace_view, ConstraintSet.WRAP_CONTENT) constrainWidth(sharedR.id.date_smartspace_view, ConstraintSet.WRAP_CONTENT) connect( @@ -128,7 +123,6 @@ constructor( dateWeatherPaddingStart, ) - // migrate addSmartspaceView from KeyguardClockSwitchController constrainHeight(sharedR.id.bc_smartspace_view, ConstraintSet.WRAP_CONTENT) constrainWidth(sharedR.id.bc_smartspace_view, ConstraintSet.MATCH_CONSTRAINT) connect( @@ -182,7 +176,6 @@ constructor( } override fun removeViews(constraintLayout: ConstraintLayout) { - if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return listOf(smartspaceView, dateWeatherView).forEach { it?.let { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt index 729759a9ad00..5d463f72d8b2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt @@ -23,7 +23,6 @@ import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.res.R import com.android.systemui.shade.NotificationPanelView import com.android.systemui.shade.ShadeDisplayAware @@ -50,16 +49,13 @@ constructor( sharedNotificationContainerBinder, ) { override fun applyConstraints(constraintSet: ConstraintSet) { - if (!MigrateClocksToBlueprint.isEnabled) { - return - } constraintSet.apply { connect( R.id.nssl_placeholder, TOP, PARENT_ID, TOP, - context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) + context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin), ) connect(R.id.nssl_placeholder, START, PARENT_ID, START) connect(R.id.nssl_placeholder, END, PARENT_ID, END) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt index 1c897237fe89..fb311a533aa2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -24,7 +24,6 @@ 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.dagger.qualifiers.Application -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -194,12 +193,7 @@ constructor( (!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt() - val translationY = - if (MigrateClocksToBlueprint.isEnabled) { - max(params.topInset - params.minViewY, burnInY) - } else { - max(params.topInset, params.minViewY + burnInY) - params.minViewY - } + val translationY = max(params.topInset - params.minViewY, burnInY) BurnInModel( translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), translationY = translationY, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceHapticViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceHapticViewModel.kt new file mode 100644 index 000000000000..890628c31c55 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceHapticViewModel.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge + +class KeyguardQuickAffordanceHapticViewModel +@AssistedInject +constructor( + @Assisted quickAffordanceViewModel: Flow<KeyguardQuickAffordanceViewModel>, + private val quickAffordanceInteractor: KeyguardQuickAffordanceInteractor, +) { + + private val activatedHistory = MutableStateFlow(ActivatedHistory(false)) + + private val launchingHapticState: Flow<HapticState> = + combine( + quickAffordanceViewModel.map { it.configKey }, + quickAffordanceInteractor.launchingFromTriggeredResult, + ) { key, launchingResult -> + val validKey = key != null && key == launchingResult?.configKey + if (validKey && launchingResult?.launched == true) { + HapticState.LAUNCH + } else { + HapticState.NO_HAPTICS + } + } + .distinctUntilChanged() + + private val toggleHapticState: Flow<HapticState> = + activatedHistory + .map { history -> + when { + history.previousValue == false && history.currentValue -> HapticState.TOGGLE_ON + history.previousValue == true && !history.currentValue -> HapticState.TOGGLE_OFF + else -> HapticState.NO_HAPTICS + } + } + .distinctUntilChanged() + + val quickAffordanceHapticState = + merge(launchingHapticState, toggleHapticState).distinctUntilChanged() + + fun resetLaunchingFromTriggeredResult() = + quickAffordanceInteractor.setLaunchingFromTriggeredResult(null) + + fun updateActivatedHistory(isActivated: Boolean) { + activatedHistory.value = + ActivatedHistory( + currentValue = isActivated, + previousValue = activatedHistory.value.currentValue, + ) + } + + enum class HapticState { + TOGGLE_ON, + TOGGLE_OFF, + LAUNCH, + NO_HAPTICS, + } + + private data class ActivatedHistory( + val currentValue: Boolean, + val previousValue: Boolean? = null, + ) + + @AssistedFactory + interface Factory { + fun create( + quickAffordanceViewModel: Flow<KeyguardQuickAffordanceViewModel> + ): KeyguardQuickAffordanceHapticViewModel + } +} 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 9066d466ceca..eaba5d5a149c 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 @@ -29,7 +29,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.domain.interactor.PulseExpansionInteractor import com.android.systemui.keyguard.shared.model.Edge -import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.GONE @@ -130,7 +129,6 @@ constructor( PrimaryBouncerToLockscreenTransitionViewModel, private val screenOffAnimationController: ScreenOffAnimationController, private val aodBurnInViewModel: AodBurnInViewModel, - private val aodAlphaViewModel: AodAlphaViewModel, private val shadeInteractor: ShadeInteractor, ) { val burnInLayerVisibility: Flow<Int> = @@ -284,15 +282,6 @@ constructor( .distinctUntilChanged() } - /** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */ - @Deprecated("only used for legacy status view") - fun lockscreenStateAlpha(viewState: ViewStateAccessor): Flow<Float> { - return aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState) - } - - /** For elements that appear and move during the animation -> AOD */ - val burnInLayerAlpha: Flow<Float> = aodAlphaViewModel.alpha - val translationY: Flow<Float> = aodBurnInViewModel.movement.map { it.translationY.toFloat() } val translationX: Flow<StateToValue> = diff --git a/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt b/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt new file mode 100644 index 000000000000..dd2525f5ca45 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/lottie/LottieTaskExt.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.lottie + +import com.airbnb.lottie.LottieComposition +import com.airbnb.lottie.LottieListener +import com.airbnb.lottie.LottieTask +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlinx.coroutines.suspendCancellableCoroutine + +/** + * Suspends until [LottieTask] is finished with a result or a failure. + * + * @return result of the [LottieTask] when it's successful + */ +suspend fun LottieTask<LottieComposition>.await() = + suspendCancellableCoroutine<LottieComposition> { continuation -> + val resultListener = + LottieListener<LottieComposition> { result -> + with(continuation) { if (!isCancelled && !isCompleted) resume(result) } + } + val failureListener = + LottieListener<Throwable> { throwable -> + with(continuation) { + if (!isCancelled && !isCompleted) resumeWithException(throwable) + } + } + addListener(resultListener) + addFailureListener(failureListener) + continuation.invokeOnCancellation { + removeListener(resultListener) + removeFailureListener(failureListener) + } + } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt index c32bd403d2e8..b4dabbe036e9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt @@ -34,13 +34,14 @@ import android.view.ViewGroup import android.view.ViewGroupOverlay import androidx.annotation.VisibleForTesting import com.android.app.animation.Interpolators +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.app.tracing.traceSection import com.android.keyguard.KeyguardViewController import com.android.systemui.Flags.mediaControlsLockscreenShadeBugFix import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dreams.DreamOverlayStateController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -68,7 +69,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapLatest -import com.android.app.tracing.coroutines.launchTraced as launch private val TAG: String = MediaHierarchyManager::class.java.simpleName @@ -115,7 +115,7 @@ constructor( wakefulnessLifecycle: WakefulnessLifecycle, shadeInteractor: ShadeInteractor, private val secureSettings: SecureSettings, - @Main private val handler: Handler, + @Background private val handler: Handler, @Application private val coroutineScope: CoroutineScope, private val splitShadeStateController: SplitShadeStateController, private val logger: MediaViewLogger, @@ -631,7 +631,7 @@ constructor( } } } - secureSettings.registerContentObserverForUserSync( + secureSettings.registerContentObserverForUserAsync( Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, settingsObserver, UserHandle.USER_ALL, 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 574ccee28faa..ab998d10287f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -366,7 +366,6 @@ public abstract class MediaOutputBaseAdapter extends / (double) seekBar.getMax()); mVolumeValueText.setText(mContext.getResources().getString( R.string.media_output_dialog_volume_percentage, percentage)); - mVolumeValueText.setVisibility(View.VISIBLE); if (mStartFromMute) { updateUnmutedVolumeIcon(device); mStartFromMute = false; diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt index 311cbfb7e632..b2696aeaabfc 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt @@ -132,7 +132,7 @@ constructor( val isDefaultNotesAppSet = noteTaskInfoResolver.resolveInfo( QUICK_AFFORDANCE, - user = controller.getUserForHandlingNotesTaking(QUICK_AFFORDANCE) + user = controller.getUserForHandlingNotesTaking(QUICK_AFFORDANCE), ) != null return when { isEnabled && isDefaultNotesAppSet -> PickerScreenState.Default() @@ -158,7 +158,7 @@ constructor( override fun onTriggered(expandable: Expandable?): OnTriggeredResult { controller.showNoteTask(entryPoint = QUICK_AFFORDANCE) - return OnTriggeredResult.Handled + return OnTriggeredResult.Handled(true) } } @@ -194,7 +194,7 @@ private fun RoleManager.createNotesRoleFlow( fun isDefaultNotesAppSetForUser() = noteTaskInfoResolver.resolveInfo( QUICK_AFFORDANCE, - user = noteTaskController.getUserForHandlingNotesTaking(QUICK_AFFORDANCE) + user = noteTaskController.getUserForHandlingNotesTaking(QUICK_AFFORDANCE), ) != null trySendBlocking(isDefaultNotesAppSetForUser()) diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index 91a3120ec770..1e608af14568 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -67,6 +67,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.shared.system.SysUiStatsLog import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.DeviceConfigProxy @@ -141,7 +142,6 @@ interface FgsManagerController { class FgsManagerControllerImpl @Inject constructor( - @ShadeDisplayAware private val context: Context, @ShadeDisplayAware private val resources: Resources, @Main private val mainExecutor: Executor, @Background private val backgroundExecutor: Executor, @@ -155,6 +155,7 @@ constructor( private val broadcastDispatcher: BroadcastDispatcher, private val dumpManager: DumpManager, private val systemUIDialogFactory: SystemUIDialog.Factory, + private val shadeDialogContextRepository: ShadeDialogContextInteractor, ) : Dumpable, FgsManagerController { companion object { @@ -388,7 +389,7 @@ constructor( override fun showDialog(expandable: Expandable?) { synchronized(lock) { if (dialog == null) { - val dialog = systemUIDialogFactory.create(context) + val dialog = systemUIDialogFactory.create(shadeDialogContextRepository.context) dialog.setTitle(R.string.fgs_manager_dialog_title) dialog.setMessage(R.string.fgs_manager_dialog_message) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt index ef7e7eb59898..84b995e1cd28 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileIcon.kt @@ -22,16 +22,21 @@ import com.android.systemui.qs.tileimpl.QSTileImpl /** * Creates a [QSTile.Icon] from an [Icon]. - * * [Icon.Loaded] -> [QSTileImpl.DrawableIcon] + * * [Icon.Loaded] with null [res] -> [QSTileImpl.DrawableIcon] + * * [Icon.Loaded] & with non null [res] -> [QSTileImpl.DrawableIconWithRes] * * [Icon.Resource] -> [QSTileImpl.ResourceIcon] */ fun Icon.asQSTileIcon(): QSTile.Icon { return when (this) { is Icon.Loaded -> { - QSTileImpl.DrawableIcon(this.drawable) + if (res == null) { + QSTileImpl.DrawableIcon(drawable) + } else { + QSTileImpl.DrawableIconWithRes(drawable, res) + } } is Icon.Resource -> { - QSTileImpl.ResourceIcon.get(this.res) + QSTileImpl.ResourceIcon.get(res) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt index 790793eab258..3049a40f18c4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt @@ -17,16 +17,16 @@ package com.android.systemui.qs.composefragment.ui import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.ClipOp import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.graphics.layer.CompositingStrategy -import androidx.compose.ui.graphics.layer.drawLayer +import androidx.compose.ui.graphics.graphicsLayer /** * Clipping modifier for clipping out the notification scrim as it slides over QS. It will clip out @@ -34,16 +34,16 @@ import androidx.compose.ui.graphics.layer.drawLayer * from the QS container. */ fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams): Modifier { - return this.drawWithCache { + return this.graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .drawWithContent { + drawContent() val params = clipParams() val left = -params.leftInset.toFloat() val right = size.width + params.rightInset.toFloat() val top = params.top.toFloat() val bottom = params.bottom.toFloat() - val graphicsLayer = obtainGraphicsLayer() - graphicsLayer.compositingStrategy = CompositingStrategy.Offscreen - graphicsLayer.record { - drawContent() + val clipSize = Size(right - left, bottom - top) + if (!clipSize.isEmpty()) { clipRect { drawRoundRect( color = Color.Black, @@ -54,9 +54,6 @@ fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams ) } } - onDrawWithContent { - drawLayer(graphicsLayer) - } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 873059ee08db..e7fa27159e9e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -675,17 +675,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta } private void add() { - if (addFromPosition(getLayoutPosition())) { - itemView.announceForAccessibility( - itemView.getContext().getText(R.string.accessibility_qs_edit_tile_added)); - } + addFromPosition(getLayoutPosition()); } private void remove() { - if (removeFromPosition(getLayoutPosition())) { - itemView.announceForAccessibility( - itemView.getContext().getText(R.string.accessibility_qs_edit_tile_removed)); - } + removeFromPosition(getLayoutPosition()); } boolean isCurrentTile() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt index b9994d7bb821..4b30645df379 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.panels.ui.compose import com.android.compose.animation.Bounceable +import com.android.systemui.grid.ui.compose.SpannedGridState import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.TileGridCell @@ -37,22 +38,37 @@ fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo( val cell = this[index].first as TileGridCell // Only look for neighbor bounceables if they are on the same row val onLastColumn = cell.onLastColumn(cell.column, columns) - val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 } - val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } + val previousTile = getOrNull(index - 1)?.takeIf { it.first.row == cell.row } + val nextTile = getOrNull(index + 1)?.takeIf { it.first.row == cell.row } return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn) } -fun List<BounceableTileViewModel>.bounceableInfo( - sizedTile: SizedTile<TileViewModel>, - index: Int, - column: Int, +inline fun List<SizedTile<TileViewModel>>.forEachWithBounceables( + positions: List<SpannedGridState.Position>, + bounceables: List<BounceableTileViewModel>, columns: Int, -): BounceableInfo { - // Only look for neighbor bounceables if they are on the same row - val onLastColumn = sizedTile.onLastColumn(column, columns) - val previousTile = getOrNull(index - 1)?.takeIf { column != 0 } - val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } - return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn) + action: (index: Int, tile: SizedTile<TileViewModel>, bounceableInfo: BounceableInfo) -> Unit, +) { + this.forEachIndexed { index, tile -> + val position = positions.getOrNull(index) + val onLastColumn = position?.column == columns - tile.width + val previousBounceable = + bounceables.getOrNull(index - 1)?.takeIf { + position != null && positions.getOrNull(index - 1)?.row == position.row + } + val nextBounceable = + bounceables.getOrNull(index + 1)?.takeIf { + position != null && positions.getOrNull(index + 1)?.row == position.row + } + val bounceableInfo = + BounceableInfo( + bounceable = bounceables[index], + previousTile = previousBounceable, + nextTile = nextBounceable, + bounceEnd = !onLastColumn, + ) + action(index, tile, bounceableInfo) + } } private fun <T> SizedTile<T>.onLastColumn(column: Int, columns: Int): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt index 2928ad117922..ceff94afd9ee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt @@ -29,6 +29,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.grid.ui.compose.VerticalSpannedGrid +import com.android.systemui.grid.ui.compose.rememberSpannedGridState import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel @@ -47,6 +48,8 @@ fun SceneScope.QuickQuickSettings( val bounceables = remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } } val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() + val gridState = rememberSpannedGridState() + val positions = gridState.positions DisposableEffect(tiles) { val token = Any() @@ -54,30 +57,34 @@ fun SceneScope.QuickQuickSettings( onDispose { tiles.forEach { it.stopListening(token) } } } val columns = viewModel.columns - var cellIndex = 0 Box(modifier = modifier) { GridAnchor() VerticalSpannedGrid( columns = columns, columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal), rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical), - spans = sizedTiles.fastMap { it.width }, + state = gridState, modifier = Modifier.sysuiResTag("qqs_tile_layout"), - ) { spanIndex -> - val it = sizedTiles[spanIndex] - val column = cellIndex % columns - cellIndex += it.width - Tile( - tile = it.tile, - iconOnly = it.isIcon, - modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), - squishiness = { squishiness }, - coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), - tileHapticsViewModelFactoryProvider = viewModel.tileHapticsViewModelFactoryProvider, - // There should be no QuickQuickSettings when the details view is enabled. - detailsViewModel = null, - ) + ) { + sizedTiles.forEachWithBounceables(positions, bounceables, columns) { + index, + sizedTile, + bounceableInfo -> + Tile( + tile = sizedTile.tile, + iconOnly = sizedTile.isIcon, + modifier = + Modifier.element(sizedTile.tile.spec.toElementKey(index)) + .span(sizedTile.width), + squishiness = { squishiness }, + coroutineScope = scope, + bounceableInfo = bounceableInfo, + tileHapticsViewModelFactoryProvider = + viewModel.tileHapticsViewModelFactoryProvider, + // There should be no QuickQuickSettings when the details view is enabled. + detailsViewModel = null, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt index d975f104d538..60c78a01bf9e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt @@ -395,7 +395,7 @@ private fun CurrentTilesGrid( val cells = remember(listState.tiles) { - listState.tiles.fastMap { Pair(it, BounceableTileViewModel()) } + listState.tiles.fastMap { tile -> Pair(tile, BounceableTileViewModel()) } } TileLazyGrid( diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt index 8fd99a52eceb..8a128896b45d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt @@ -23,17 +23,18 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.util.fastMap import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.grid.ui.compose.VerticalSpannedGrid +import com.android.systemui.grid.ui.compose.rememberSpannedGridState import com.android.systemui.haptics.msdl.qs.TileHapticsViewModelFactoryProvider import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS import com.android.systemui.qs.panels.shared.model.SizedTileImpl import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout import com.android.systemui.qs.panels.ui.compose.bounceableInfo +import com.android.systemui.qs.panels.ui.compose.forEachWithBounceables import com.android.systemui.qs.panels.ui.compose.rememberEditListState import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel @@ -83,27 +84,32 @@ constructor( remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } } val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() - var cellIndex = 0 + val gridState = rememberSpannedGridState() + val positions = gridState.positions VerticalSpannedGrid( columns = columns, + state = gridState, columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal), rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical), - spans = sizedTiles.fastMap { it.width }, - ) { spanIndex -> - val it = sizedTiles[spanIndex] - val column = cellIndex % columns - cellIndex += it.width - Tile( - tile = it.tile, - iconOnly = iconTilesViewModel.isIconTile(it.tile.spec), - modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), - squishiness = { squishiness }, - tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider, - coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), - detailsViewModel = detailsViewModel, - ) + ) { + sizedTiles.forEachWithBounceables(positions, bounceables, columns) { + index, + sizedTile, + bounceableInfo -> + Tile( + tile = sizedTile.tile, + iconOnly = iconTilesViewModel.isIconTile(sizedTile.tile.spec), + modifier = + Modifier.element(sizedTile.tile.spec.toElementKey(index)) + .span(sizedTile.width), + squishiness = { squishiness }, + tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider, + coroutineScope = scope, + bounceableInfo = bounceableInfo, + detailsViewModel = detailsViewModel, + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt index 85db95203b45..f3c06a481fc2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt @@ -54,7 +54,7 @@ fun EditModeButton( ) { Icon( imageVector = Icons.Default.Edit, - contentDescription = stringResource(id = R.string.qs_edit), + contentDescription = stringResource(id = R.string.accessibility_quick_settings_edit), ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 42a0cb1004f4..b7ff63cdc1fb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -41,6 +41,7 @@ import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.DataSaverController; @@ -56,6 +57,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements private final DataSaverController mDataSaverController; private final DialogTransitionAnimator mDialogTransitionAnimator; private final SystemUIDialog.Factory mSystemUIDialogFactory; + private final ShadeDialogContextInteractor mShadeDialogContextInteractor; @Inject public DataSaverTile( @@ -70,13 +72,15 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements QSLogger qsLogger, DataSaverController dataSaverController, DialogTransitionAnimator dialogTransitionAnimator, - SystemUIDialog.Factory systemUIDialogFactory + SystemUIDialog.Factory systemUIDialogFactory, + ShadeDialogContextInteractor shadeDialogContextInteractor ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mDataSaverController = dataSaverController; mDialogTransitionAnimator = dialogTransitionAnimator; mSystemUIDialogFactory = systemUIDialogFactory; + mShadeDialogContextInteractor = shadeDialogContextInteractor; mDataSaverController.observe(getLifecycle(), this); } @@ -102,7 +106,8 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements // Show a dialog to confirm first. Dialogs shown by the DialogTransitionAnimator must be // created and shown on the main thread, so we post it to the UI handler. mUiHandler.post(() -> { - SystemUIDialog dialog = mSystemUIDialogFactory.create(mContext); + SystemUIDialog dialog = mSystemUIDialogFactory.create( + mShadeDialogContextInteractor.getContext()); dialog.setTitle(com.android.internal.R.string.data_saver_enable_title); dialog.setMessage(com.android.internal.R.string.data_saver_description); dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt index 989fc0fd6f44..5ba1527dbf69 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt @@ -22,6 +22,7 @@ import android.os.Looper import android.service.quicksettings.Tile import com.android.internal.logging.MetricsLogger import com.android.systemui.animation.Expandable +import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -92,7 +93,8 @@ constructor( state?.apply { this.state = tileState.activationState.legacyState - icon = maybeLoadResourceIcon(tileState.iconRes ?: R.drawable.ic_qs_notes) + icon = + maybeLoadResourceIcon((tileState.icon as Icon.Loaded).res ?: R.drawable.ic_qs_notes) label = tileState.label contentDescription = tileState.contentDescription expandedAccessibilityClassName = tileState.expandedAccessibilityClassName diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java index 19b45d50c594..7516ca030d4b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java @@ -193,7 +193,7 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern if (mJob == null) { mJob = WifiUtils.checkWepAllowed(mContext, mCoroutineScope, wifiEntry.getSsid(), WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, intent -> { - mInternetDialogController.startActivity(intent, view); + mInternetDialogController.startActivityForDialog(intent); return null; }, () -> { wifiConnect(wifiEntry, view); @@ -211,7 +211,7 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern true /* connectForCaller */); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - mContext.startActivity(intent); + mInternetDialogController.startActivityForDialog(intent); return; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index dbe1ae90b3f6..7036ef914a1c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -781,6 +781,10 @@ public class InternetDialogController implements AccessPointController.AccessPoi mActivityStarter.postStartActivityDismissingKeyguard(intent, 0, controller); } + void startActivityForDialog(Intent intent) { + mActivityStarter.startActivity(intent, false /* dismissShade */); + } + void launchNetworkSetting(View view) { startActivity(getSettingsIntent(), view); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java index 70c2a2a0d55a..5e9deec58c58 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java @@ -72,6 +72,7 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; import com.android.systemui.shade.ShadeDisplayAware; +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.wifitrackerlib.WifiEntry; @@ -104,9 +105,9 @@ public class InternetDialogDelegate implements private final Handler mHandler; private final Executor mBackgroundExecutor; private final DialogTransitionAnimator mDialogTransitionAnimator; - private final Context mContext; private final boolean mAboveStatusBar; private final SystemUIDialog.Factory mSystemUIDialogFactory; + private final ShadeDialogContextInteractor mShadeDialogContextInteractor; @VisibleForTesting protected InternetAdapter mAdapter; @@ -204,10 +205,11 @@ public class InternetDialogDelegate implements @Main Handler handler, @Background Executor executor, KeyguardStateController keyguardStateController, - SystemUIDialog.Factory systemUIDialogFactory) { - mContext = context; + SystemUIDialog.Factory systemUIDialogFactory, + ShadeDialogContextInteractor shadeDialogContextInteractor) { mAboveStatusBar = aboveStatusBar; mSystemUIDialogFactory = systemUIDialogFactory; + mShadeDialogContextInteractor = shadeDialogContextInteractor; if (DEBUG) { Log.d(TAG, "Init InternetDialog"); } @@ -230,7 +232,8 @@ public class InternetDialogDelegate implements @Override public SystemUIDialog createDialog() { - SystemUIDialog dialog = mSystemUIDialogFactory.create(this, mContext); + SystemUIDialog dialog = mSystemUIDialogFactory.create(this, + mShadeDialogContextInteractor.getContext()); if (!mAboveStatusBar) { dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt index 34c2ec90f1e8..80d429ce2716 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt @@ -35,13 +35,13 @@ constructor(@ShadeDisplayAware private val resources: Resources, val theme: Them override fun map(config: QSTileConfig, data: AirplaneModeTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = + val iconRes = if (data.isEnabled) { R.drawable.qs_airplane_icon_on } else { R.drawable.qs_airplane_icon_off } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) if (data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = resources.getStringArray(R.array.tile_states_airplane)[2] diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt index a72992db4496..d56d9944dbb8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt @@ -84,8 +84,8 @@ constructor( secondaryLabel = resources.getString(R.string.qs_alarm_tile_no_alarm) } } - iconRes = R.drawable.ic_alarm - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = R.drawable.ic_alarm + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) sideViewIcon = QSTileState.SideViewIcon.Chevron contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapper.kt index e116d8cef2ee..72759c5bb066 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapper.kt @@ -38,10 +38,10 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { label = resources.getString(R.string.battery_detail_switch_title) contentDescription = label - iconRes = + val iconRes = if (data.isPowerSaving) R.drawable.qs_battery_saver_icon_on else R.drawable.qs_battery_saver_icon_off - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) sideViewIcon = QSTileState.SideViewIcon.None if (data.isPluggedIn) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt index 21b9f659dde4..e5a0fe8ed048 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt @@ -37,8 +37,8 @@ constructor( override fun map(config: QSTileConfig, data: ColorCorrectionTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { val subtitleArray = resources.getStringArray(R.array.tile_states_color_correction) - iconRes = R.drawable.ic_qs_color_correction - icon = Icon.Loaded(resources.getDrawable(R.drawable.ic_qs_color_correction)!!, null) + val iconRes = R.drawable.ic_qs_color_correction + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) if (data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = subtitleArray[2] diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt index 2dfb1fc4fe98..32ccba6f1fa5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt @@ -35,14 +35,14 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the override fun map(config: QSTileConfig, data: FlashlightTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = + val iconRes = if (data is FlashlightTileModel.FlashlightAvailable && data.isEnabled) { R.drawable.qs_flashlight_icon_on } else { R.drawable.qs_flashlight_icon_off } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = label diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapper.kt index 7f41cbd322dd..c571b136e18b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapper.kt @@ -36,8 +36,8 @@ constructor( override fun map(config: QSTileConfig, data: FontScalingTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = R.drawable.ic_qs_font_scaling - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = R.drawable.ic_qs_font_scaling + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = label activationState = QSTileState.ActivationState.ACTIVE sideViewIcon = QSTileState.SideViewIcon.Chevron diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapper.kt index 4c302b363c3b..12f71491c7b4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapper.kt @@ -37,8 +37,8 @@ constructor( override fun map(config: QSTileConfig, data: HearingDevicesTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { label = resources.getString(R.string.quick_settings_hearing_devices_label) - iconRes = R.drawable.qs_hearing_devices_icon - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = R.drawable.qs_hearing_devices_icon + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) sideViewIcon = QSTileState.SideViewIcon.Chevron contentDescription = label if (data.isAnyActiveHearingDevice) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt index 1a6876d0b765..7ad01e463399 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt @@ -61,11 +61,11 @@ constructor( when (val dataIcon = data.icon) { is InternetTileIconModel.ResourceId -> { - iconRes = dataIcon.resId icon = Icon.Loaded( resources.getDrawable(dataIcon.resId, theme), contentDescription = null, + dataIcon.resId, ) } @@ -76,11 +76,11 @@ constructor( } is InternetTileIconModel.Satellite -> { - iconRes = dataIcon.resourceIcon.res // level is inferred from res icon = Icon.Loaded( resources.getDrawable(dataIcon.resourceIcon.res, theme), contentDescription = null, + dataIcon.resourceIcon.res, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt index 8d35b2413bad..05590e803ffa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt @@ -35,7 +35,7 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the override fun map(config: QSTileConfig, data: ColorInversionTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { val subtitleArray = resources.getStringArray(R.array.tile_states_inversion) - + val iconRes: Int if (data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = subtitleArray[2] @@ -45,7 +45,7 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the secondaryLabel = subtitleArray[1] iconRes = R.drawable.qs_invert_colors_icon_off } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingMapper.kt index 3557c1a4ac9d..afb137e1e92f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingMapper.kt @@ -39,6 +39,7 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the Icon.Loaded( resources.getDrawable(R.drawable.qs_record_issue_icon_on, theme), null, + R.drawable.qs_record_issue_icon_on, ) } else { activationState = QSTileState.ActivationState.INACTIVE @@ -46,6 +47,7 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the Icon.Loaded( resources.getDrawable(R.drawable.qs_record_issue_icon_off, theme), null, + R.drawable.qs_record_issue_icon_off, ) } supportedActions = setOf(QSTileState.UserAction.CLICK) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt index dfc24a10c491..ced5a4f099a2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt @@ -35,13 +35,13 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the override fun map(config: QSTileConfig, data: LocationTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = + val iconRes = if (data.isEnabled) { R.drawable.qs_location_icon_on } else { R.drawable.qs_location_icon_off } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) label = resources.getString(R.string.quick_settings_location_label) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt index 9b2880b6d47f..479f61823912 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt @@ -17,10 +17,10 @@ package com.android.systemui.qs.tiles.impl.modes.domain.interactor import android.content.Context +import android.graphics.drawable.Drawable import android.os.UserHandle import com.android.app.tracing.coroutines.flow.flowName import com.android.systemui.common.shared.model.Icon -import com.android.systemui.common.shared.model.asIcon import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.modes.shared.ModesUi import com.android.systemui.modes.shared.ModesUiIcons @@ -31,7 +31,6 @@ import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes -import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow @@ -68,37 +67,29 @@ constructor( suspend fun getCurrentTileModel() = buildTileData(zenModeInteractor.getActiveModes()) private fun buildTileData(activeModes: ActiveZenModes): ModesTileModel { - if (ModesUiIcons.isEnabled) { - val tileIcon = getTileIcon(activeModes.mainMode) - return ModesTileModel( - isActivated = activeModes.isAnyActive(), - icon = tileIcon.icon, - iconResId = tileIcon.resId, - activeModes = activeModes.modeNames, - ) - } else { - return ModesTileModel( - isActivated = activeModes.isAnyActive(), - icon = context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(), - iconResId = ModesTile.ICON_RES_ID, - activeModes = activeModes.modeNames, - ) - } - } + val drawable: Drawable + val iconRes: Int? + val activeMode = activeModes.mainMode - private data class TileIcon(val icon: Icon.Loaded, val resId: Int?) - - private fun getTileIcon(activeMode: ZenModeInfo?): TileIcon { - return if (activeMode != null) { + if (ModesUiIcons.isEnabled && activeMode != null) { // ZenIconKey.resPackage is null if its resId is a system icon. - if (activeMode.icon.key.resPackage == null) { - TileIcon(activeMode.icon.drawable.asIcon(), activeMode.icon.key.resId) - } else { - TileIcon(activeMode.icon.drawable.asIcon(), null) - } + iconRes = + if (activeMode.icon.key.resPackage == null) { + activeMode.icon.key.resId + } else { + null + } + drawable = activeMode.icon.drawable } else { - TileIcon(context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(), ModesTile.ICON_RES_ID) + iconRes = ModesTile.ICON_RES_ID + drawable = context.getDrawable(iconRes)!! } + + return ModesTileModel( + isActivated = activeModes.isAnyActive(), + icon = Icon.Loaded(drawable, null, iconRes), + activeModes = activeModes.modeNames, + ) } override fun availability(user: UserHandle): Flow<Boolean> = flowOf(ModesUi.isEnabled) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt index db4812342050..d0eacbc9a957 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt @@ -21,12 +21,10 @@ import com.android.systemui.common.shared.model.Icon data class ModesTileModel( val isActivated: Boolean, val activeModes: List<String>, - val icon: Icon.Loaded, - /** - * Resource id corresponding to [icon]. Will only be present if it's know to correspond to a - * resource with a known id in SystemUI (such as resources from `android.R`, - * `com.android.internal.R`, or `com.android.systemui.res` itself). + * icon.res will only be present if it is known to correspond to a resource with a known id in + * SystemUI (such as resources from `android.R`, `com.android.internal.R`, or + * `com.android.systemui.res` itself). */ - val iconResId: Int? = null + val icon: Icon.Loaded, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt index 1507ef4b3b58..99ae3b8db709 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt @@ -34,7 +34,6 @@ constructor(@ShadeDisplayAware private val resources: Resources, val theme: Reso QSTileDataToStateMapper<ModesTileModel> { override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = data.iconResId icon = data.icon activationState = if (data.isActivated) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapper.kt index 3569e4d0b42c..16b36289ad95 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapper.kt @@ -49,7 +49,7 @@ constructor( supportedActions = setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) sideViewIcon = QSTileState.SideViewIcon.None - + val iconRes: Int if (data.isActivated) { activationState = QSTileState.ActivationState.ACTIVE iconRes = R.drawable.qs_nightlight_icon_on @@ -58,7 +58,7 @@ constructor( iconRes = R.drawable.qs_nightlight_icon_off } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) secondaryLabel = getSecondaryLabel(data, resources) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapper.kt index a5436192af39..ecdd71170cda 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapper.kt @@ -35,8 +35,8 @@ constructor( ) : QSTileDataToStateMapper<NotesTileModel> { override fun map(config: QSTileConfig, data: NotesTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { - iconRes = R.drawable.ic_qs_notes - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null) + val iconRes = R.drawable.ic_qs_notes + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = label activationState = QSTileState.ActivationState.INACTIVE sideViewIcon = QSTileState.SideViewIcon.Chevron diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt index 76f1e8b8760c..5b3ea93ab1ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt @@ -38,8 +38,8 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { val subtitleArray = resources.getStringArray(R.array.tile_states_onehanded) label = resources.getString(R.string.quick_settings_onehanded_label) - iconRes = com.android.internal.R.drawable.ic_qs_one_handed_mode - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = com.android.internal.R.drawable.ic_qs_one_handed_mode + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) if (data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE secondaryLabel = subtitleArray[2] diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt index c546250e73d2..21e92d3a1972 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt @@ -38,8 +38,8 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { label = resources.getString(R.string.qr_code_scanner_title) contentDescription = label - iconRes = R.drawable.ic_qr_code_scanner - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = R.drawable.ic_qr_code_scanner + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) sideViewIcon = QSTileState.SideViewIcon.Chevron supportedActions = setOf(QSTileState.UserAction.CLICK) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapper.kt index 66d0f96fdcde..66759cdfd1a6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapper.kt @@ -37,6 +37,7 @@ constructor( override fun map(config: QSTileConfig, data: ReduceBrightColorsTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { + val iconRes: Int if (data.isEnabled) { activationState = QSTileState.ActivationState.ACTIVE iconRes = R.drawable.qs_extra_dim_icon_on @@ -50,7 +51,7 @@ constructor( resources .getStringArray(R.array.tile_states_reduce_brightness)[Tile.STATE_INACTIVE] } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) label = resources.getString(com.android.internal.R.string.reduce_bright_colors_feature_name) contentDescription = label diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt index a0144221577d..000c7025e32b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt @@ -42,7 +42,7 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { label = resources.getString(R.string.quick_settings_rotation_unlocked_label) contentDescription = resources.getString(R.string.accessibility_quick_settings_rotation) - + val iconRes: Int if (data.isRotationLocked) { activationState = QSTileState.ActivationState.INACTIVE secondaryLabel = EMPTY_SECONDARY_STRING @@ -57,7 +57,7 @@ constructor( } iconRes = R.drawable.qs_auto_rotate_icon_on } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) if (isDeviceFoldable(resources, deviceStateManager)) { secondaryLabel = getSecondaryLabelWithPosture(activationState) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt index aea4967c546c..1d5cf29f2462 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt @@ -36,6 +36,7 @@ constructor( override fun map(config: QSTileConfig, data: DataSaverTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { with(data) { + val iconRes: Int if (isEnabled) { activationState = QSTileState.ActivationState.ACTIVE iconRes = R.drawable.qs_data_saver_icon_on @@ -45,7 +46,7 @@ constructor( iconRes = R.drawable.qs_data_saver_icon_off secondaryLabel = resources.getStringArray(R.array.tile_states_saver)[1] } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt index f3136e015acf..0a61e3cbe616 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt @@ -38,7 +38,7 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { label = resources.getString(R.string.quick_settings_screen_record_label) supportedActions = setOf(QSTileState.UserAction.CLICK) - + val iconRes: Int when (data) { is ScreenRecordModel.Recording -> { activationState = QSTileState.ActivationState.ACTIVE @@ -61,7 +61,7 @@ constructor( resources.getString(R.string.quick_settings_screen_record_start) } } - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) contentDescription = if (TextUtils.isEmpty(secondaryLabel)) label diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapper.kt index 73e61b7d178e..f54f46c01dee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/ui/SensorPrivacyToggleTileMapper.kt @@ -50,8 +50,8 @@ constructor( contentDescription = label supportedActions = setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) - iconRes = sensorPrivacyTileResources.getIconRes(data.isBlocked) - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + val iconRes = sensorPrivacyTileResources.getIconRes(data.isBlocked) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) sideViewIcon = QSTileState.SideViewIcon.None if (data.isBlocked) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt index e9aa46c5f253..5933d65bc61f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt @@ -116,11 +116,11 @@ constructor(@ShadeDisplayAware private val resources: Resources, private val the } } - iconRes = + val iconRes = if (activationState == QSTileState.ActivationState.ACTIVE) R.drawable.qs_light_dark_theme_icon_on else R.drawable.qs_light_dark_theme_icon_off - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), null) + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) supportedActions = if (activationState == QSTileState.ActivationState.UNAVAILABLE) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt index 6a3195a493c8..5b462ba074ec 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt @@ -41,8 +41,8 @@ constructor( QSTileState.build(resources, theme, config.uiConfig) { label = getTileLabel()!! contentDescription = label - iconRes = com.android.internal.R.drawable.stat_sys_managed_profile_status - icon = Icon.Loaded(resources.getDrawable(iconRes!!, theme), contentDescription = null) + val iconRes = com.android.internal.R.drawable.stat_sys_managed_profile_status + icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) when (data) { is WorkModeTileModel.HasActiveProfile -> { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt index 8394be5e0a38..c6af729cd4a7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt @@ -36,7 +36,6 @@ import kotlin.reflect.KClass */ data class QSTileState( val icon: Icon?, - val iconRes: Int?, val label: CharSequence, val activationState: ActivationState, val secondaryLabel: CharSequence?, @@ -58,7 +57,7 @@ data class QSTileState( ): QSTileState { val iconDrawable = resources.getDrawable(config.iconRes, theme) return build( - Icon.Loaded(iconDrawable, null), + Icon.Loaded(iconDrawable, null, config.iconRes), resources.getString(config.labelRes), builder, ) @@ -115,7 +114,6 @@ data class QSTileState( } class Builder(var icon: Icon?, var label: CharSequence) { - var iconRes: Int? = null var activationState: ActivationState = ActivationState.INACTIVE var secondaryLabel: CharSequence? = null var supportedActions: Set<UserAction> = setOf(UserAction.CLICK) @@ -128,7 +126,6 @@ data class QSTileState( fun build(): QSTileState = QSTileState( icon, - iconRes, label, activationState, secondaryLabel, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt index 632eeefcb462..c34edc81bfe7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -260,8 +260,8 @@ constructor( icon = when (val stateIcon = viewModelState.icon) { is Icon.Loaded -> - if (viewModelState.iconRes == null) DrawableIcon(stateIcon.drawable) - else DrawableIconWithRes(stateIcon.drawable, viewModelState.iconRes) + if (stateIcon.res == null) DrawableIcon(stateIcon.drawable) + else DrawableIconWithRes(stateIcon.drawable, stateIcon.res) is Icon.Resource -> ResourceIcon.get(stateIcon.res) null -> null } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt index 8c54ab40c680..862dba1e7294 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -17,7 +17,6 @@ package com.android.systemui.qs.user import android.app.Dialog -import android.content.Context import android.content.DialogInterface import android.content.DialogInterface.BUTTON_NEUTRAL import android.content.Intent @@ -34,6 +33,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.qs.tiles.UserDetailView import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.user.ui.dialog.DialogShowerImpl import javax.inject.Inject @@ -50,6 +50,7 @@ constructor( private val dialogTransitionAnimator: DialogTransitionAnimator, private val uiEventLogger: UiEventLogger, private val dialogFactory: SystemUIDialog.Factory, + private val shadeDialogContextInteractor: ShadeDialogContextInteractor, ) { companion object { @@ -63,7 +64,8 @@ constructor( * Populate the dialog with information from and adapter obtained from * [userDetailViewAdapterProvider] and show it as launched from [expandable]. */ - fun showDialog(context: Context, expandable: Expandable) { + fun showDialog(expandable: Expandable) { + val context = shadeDialogContextInteractor.context with(dialogFactory.create(context)) { setShowForAllUsers(true) setCanceledOnTouchOutside(true) diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java index a7b51faaed57..10ac2cf76763 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java @@ -16,6 +16,8 @@ package com.android.systemui.scrim; +import static com.android.systemui.Flags.notificationShadeBlur; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -214,8 +216,7 @@ public class ScrimDrawable extends Drawable { public void draw(@NonNull Canvas canvas) { mPaint.setColor(mMainColor); mPaint.setAlpha(mAlpha); - if (WindowBlurFlag.isEnabled()) { - // TODO(b/370555223): Match the alpha to the visual spec when it is finalized. + if (notificationShadeBlur() || WindowBlurFlag.isEnabled()) { // TODO (b/381263600), wire this at ScrimController, move it to PrimaryBouncerTransition mPaint.setAlpha((int) (0.5f * mAlpha)); } diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java index 4bfa61e9dcd4..0f80e7432a54 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java @@ -16,6 +16,8 @@ package com.android.systemui.scrim; +import static com.android.systemui.Flags.notificationShadeBlur; + import static java.lang.Float.isNaN; import android.annotation.NonNull; @@ -39,13 +41,12 @@ import androidx.core.graphics.ColorUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; +import com.android.systemui.res.R; import com.android.systemui.shade.TouchLogger; import com.android.systemui.util.LargeScreenUtils; import java.util.concurrent.Executor; -import static com.android.systemui.Flags.notificationShadeBlur; - /** * A view which can draw a scrim. This view maybe be used in multiple windows running on different * threads, but is controlled by {@link com.android.systemui.statusbar.phone.ScrimController} so we @@ -253,8 +254,11 @@ public class ScrimView extends View { mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor, tintAmount); } if (notificationShadeBlur()) { - // TODO(b/370555223): Fix color and transparency to match visual spec exactly - mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), Color.GRAY, 0.5f); + int layerAbove = ColorUtils.setAlphaComponent( + getResources().getColor(R.color.shade_panel, null), + (int) (0.4f * 255)); + int layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.1f * 255)); + mainTinted = ColorUtils.compositeColors(layerAbove, layerBelow); } drawable.setColor(mainTinted, animated); } else { diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt index e1631ccdcb06..bbb13d5c1dfe 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt @@ -61,9 +61,18 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider { /** Callback for notifying of changes. */ @WeaklyReferencedCallback interface Callback { - /** Notifies that the current user will be changed. */ + /** + * Same as {@link onBeforeUserSwitching(Int, Runnable)} but the callback will be called + * automatically after the completion of this method. + */ fun onBeforeUserSwitching(newUser: Int) {} + /** Notifies that the current user will be changed. */ + fun onBeforeUserSwitching(newUser: Int, resultCallback: Runnable) { + onBeforeUserSwitching(newUser) + resultCallback.run() + } + /** * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be called * automatically after the completion of this method. diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index b7a3aedc565e..42d83637ec1a 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -196,8 +196,9 @@ internal constructor( private fun registerUserSwitchObserver() { iActivityManager.registerUserSwitchObserver( object : UserSwitchObserver() { - override fun onBeforeUserSwitching(newUserId: Int) { + override fun onBeforeUserSwitching(newUserId: Int, reply: IRemoteCallback?) { handleBeforeUserSwitching(newUserId) + reply?.sendResult(null) } override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) { @@ -236,8 +237,7 @@ internal constructor( setUserIdInternal(newUserId) notifySubscribers { callback, resultCallback -> - callback.onBeforeUserSwitching(newUserId) - resultCallback.run() + callback.onBeforeUserSwitching(newUserId, resultCallback) } .await() } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 9e8858318943..28c675e2bbf4 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -58,7 +58,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.res.Resources; -import android.database.ContentObserver; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Rect; @@ -69,7 +68,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Trace; import android.os.UserManager; -import android.provider.Settings; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; @@ -106,10 +104,8 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUnfoldTransition; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; -import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.Gefingerpoken; @@ -221,10 +217,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.TapAgainViewController; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.SplitShadeStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.Compile; @@ -309,7 +302,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final ShadeHeadsUpChangedListener mOnHeadsUpChangedListener = new ShadeHeadsUpChangedListener(); private final ConfigurationListener mConfigurationListener = new ConfigurationListener(); - private final SettingsChangeObserver mSettingsChangeObserver; private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener(); private final NotificationPanelView mView; private final VibratorHelper mVibratorHelper; @@ -331,8 +323,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final MediaHierarchyManager mMediaHierarchyManager; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; - private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; - private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; private final FragmentService mFragmentService; private final IStatusBarService mStatusBarService; @@ -381,8 +371,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private float mKeyguardNotificationTopPadding; /** Current max allowed keyguard notifications determined by measuring the panel. */ private int mMaxAllowedKeyguardNotifications; - private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; - private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarViewController mKeyguardStatusBarViewController; private KeyguardStatusViewController mKeyguardStatusViewController; private NotificationsQuickSettingsContainer mNotificationContainerParent; @@ -394,8 +382,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private OpenCloseListener mOpenCloseListener; private GestureRecorder mGestureRecorder; - private boolean mKeyguardQsUserSwitchEnabled; - private boolean mKeyguardUserSwitcherEnabled; private boolean mDozing; private boolean mDozingOnDown; private boolean mBouncerShowing; @@ -691,8 +677,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump NotificationsQSContainerController notificationsQSContainerController, NotificationStackScrollLayoutController notificationStackScrollLayoutController, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, - KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, - KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, LockscreenShadeTransitionController lockscreenShadeTransitionController, AuthController authController, @@ -841,11 +825,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory; mDepthController = notificationShadeDepthController; mContentResolver = contentResolver; - mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; - mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; mFragmentService = fragmentService; mStatusBarService = statusBarService; - mSettingsChangeObserver = new SettingsChangeObserver(handler); mSplitShadeStateController = splitShadeStateController; mSplitShadeEnabled = mSplitShadeStateController.shouldUseSplitNotificationShade(mResources); @@ -874,7 +855,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mLockscreenShadeTransitionController = lockscreenShadeTransitionController; dynamicPrivacyController.addListener(this::onDynamicPrivacyChanged); quickSettingsController.setExpansionHeightListener(this::onQsSetExpansionHeightCalled); - quickSettingsController.setQsStateUpdateListener(this::onQsStateUpdated); quickSettingsController.setApplyClippingImmediatelyListener( this::onQsClippingImmediatelyApplied); quickSettingsController.setFlingQsWithoutClickListener(this::onFlingQsWithoutClick); @@ -917,7 +897,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardUnfoldTransition = unfoldComponent.map( SysUIUnfoldComponent::getKeyguardUnfoldTransition); - updateUserSwitcherFlags(); mKeyguardClockInteractor = keyguardClockInteractor; KeyguardLongPressViewBinder.bind( mView.requireViewById(R.id.keyguard_long_press), @@ -1009,30 +988,14 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump void onFinishInflate() { loadDimens(); - FrameLayout userAvatarContainer = null; - KeyguardUserSwitcherView keyguardUserSwitcherView = null; - - if (mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled( - mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user))) { - if (mKeyguardQsUserSwitchEnabled) { - ViewStub stub = mView.findViewById(R.id.keyguard_qs_user_switch_stub); - userAvatarContainer = (FrameLayout) stub.inflate(); - } else { - ViewStub stub = mView.findViewById(R.id.keyguard_user_switcher_stub); - keyguardUserSwitcherView = (KeyguardUserSwitcherView) stub.inflate(); - } - } - mKeyguardStatusBarViewController = mKeyguardStatusBarViewComponentFactory.build( mView.findViewById(R.id.keyguard_header), mShadeViewStateProvider) .getKeyguardStatusBarViewController(); mKeyguardStatusBarViewController.init(); - mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); - updateViewControllers(userAvatarContainer, keyguardUserSwitcherView); - + updateStatusViewController(); mNotificationStackScrollLayoutController.setOnHeightChangedListener( new NsslHeightChangedListener()); mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener( @@ -1225,39 +1188,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } } - private void updateViewControllers( - FrameLayout userAvatarView, - KeyguardUserSwitcherView keyguardUserSwitcherView) { - updateStatusViewController(); - if (mKeyguardUserSwitcherController != null) { - // Try to close the switcher so that callbacks are triggered if necessary. - // Otherwise, NPV can get into a state where some of the views are still hidden - mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(false); - } - - mKeyguardQsUserSwitchController = null; - mKeyguardUserSwitcherController = null; - - // Re-associate the KeyguardUserSwitcherController - if (userAvatarView != null) { - KeyguardQsUserSwitchComponent userSwitcherComponent = - mKeyguardQsUserSwitchComponentFactory.build(userAvatarView); - mKeyguardQsUserSwitchController = - userSwitcherComponent.getKeyguardQsUserSwitchController(); - mKeyguardQsUserSwitchController.init(); - mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true); - } else if (keyguardUserSwitcherView != null) { - KeyguardUserSwitcherComponent userSwitcherComponent = - mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView); - mKeyguardUserSwitcherController = - userSwitcherComponent.getKeyguardUserSwitcherController(); - mKeyguardUserSwitcherController.init(); - mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(true); - } else { - mKeyguardStatusBarViewController.setKeyguardUserSwitcherEnabled(false); - } - } - /** Updates the StatusBarViewController and updates any that depend on it. */ public void updateStatusViewController() { // Re-associate the KeyguardStatusViewController @@ -1391,29 +1321,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // we need to update KeyguardStatusView constraints after reinflating it updateResources(); - - // Re-inflate the keyguard user switcher group. - updateUserSwitcherFlags(); - boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled( - mResources.getBoolean(R.bool.qs_show_user_switcher_for_single_user)); - boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled; - boolean showKeyguardUserSwitcher = - !mKeyguardQsUserSwitchEnabled - && mKeyguardUserSwitcherEnabled - && isUserSwitcherEnabled; - FrameLayout userAvatarView = (FrameLayout) reInflateStub( - R.id.keyguard_qs_user_switch_view /* viewId */, - R.id.keyguard_qs_user_switch_stub /* stubId */, - R.layout.keyguard_qs_user_switch /* layoutId */, - showQsUserSwitch /* enabled */); - KeyguardUserSwitcherView keyguardUserSwitcherView = - (KeyguardUserSwitcherView) reInflateStub( - R.id.keyguard_user_switcher_view /* viewId */, - R.id.keyguard_user_switcher_stub /* stubId */, - R.layout.keyguard_user_switcher /* layoutId */, - showKeyguardUserSwitcher /* enabled */); - - updateViewControllers(userAvatarView, keyguardUserSwitcherView); + updateStatusViewController(); mStatusBarStateListener.onDozeAmountChanged(mStatusBarStateController.getDozeAmount(), mStatusBarStateController.getInterpolatedDozeAmount()); @@ -1424,20 +1332,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump false, mBarState); } - if (mKeyguardQsUserSwitchController != null) { - mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( - mBarState, - false, - false, - mBarState); - } - if (mKeyguardUserSwitcherController != null) { - mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( - mBarState, - false, - false, - mBarState); - } } private void attachSplitShadeMediaPlayerContainer(FrameLayout container) { @@ -1563,7 +1457,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } private void updateClockAppearance() { - int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard; boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange(); if (MigrateClocksToBlueprint.isEnabled()) { @@ -1573,11 +1466,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump shouldAnimateClockChange); } updateKeyguardStatusViewAlignment(/* animate= */true); - int userSwitcherHeight = mKeyguardQsUserSwitchController != null - ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0; - if (mKeyguardUserSwitcherController != null) { - userSwitcherHeight = mKeyguardUserSwitcherController.getHeight(); - } float expandedFraction = mScreenOffAnimationController.shouldExpandNotifications() ? 1.0f : getExpandedFraction(); @@ -1595,8 +1483,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mStatusBarHeaderHeightKeyguard, expandedFraction, mKeyguardStatusViewController.getLockscreenHeight(), - userSwitcherHeight, - userSwitcherPreferredY, darkAmount, mOverStretchAmount, bypassEnabled, mQsController.getHeaderHeight(), @@ -1621,18 +1507,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mClockPositionResult.clockX, mClockPositionResult.clockY, mClockPositionResult.clockScale, animateClock); } - if (mKeyguardQsUserSwitchController != null) { - mKeyguardQsUserSwitchController.updatePosition( - mClockPositionResult.clockX, - mClockPositionResult.userSwitchY, - animateClock); - } - if (mKeyguardUserSwitcherController != null) { - mKeyguardUserSwitcherController.updatePosition( - mClockPositionResult.clockX, - mClockPositionResult.userSwitchY, - animateClock); - } updateNotificationTranslucency(); updateClock(); } @@ -1868,13 +1742,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardStatusViewController .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true); } - - if (mKeyguardQsUserSwitchController != null) { - mKeyguardQsUserSwitchController.setAlpha(alpha); - } - if (mKeyguardUserSwitcherController != null) { - mKeyguardUserSwitcherController.setAlpha(alpha); - } } @Override @@ -3248,24 +3115,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } @Override - public void startBouncerPreHideAnimation() { - if (mKeyguardQsUserSwitchController != null) { - mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility( - mBarState, - true /* keyguardFadingAway */, - false /* goingToFullShade */, - mBarState); - } - if (mKeyguardUserSwitcherController != null) { - mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility( - mBarState, - true /* keyguardFadingAway */, - false /* goingToFullShade */, - mBarState); - } - } - - @Override public ShadeFoldAnimatorImpl getShadeFoldAnimator() { return mShadeFoldAnimator; } @@ -3394,8 +3243,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump ipw.println(mMaxAllowedKeyguardNotifications); ipw.print("mAnimateNextPositionUpdate="); ipw.println(mAnimateNextPositionUpdate); ipw.print("isPanelExpanded()="); ipw.println(isPanelExpanded()); - ipw.print("mKeyguardQsUserSwitchEnabled="); ipw.println(mKeyguardQsUserSwitchEnabled); - ipw.print("mKeyguardUserSwitcherEnabled="); ipw.println(mKeyguardUserSwitcherEnabled); ipw.print("mDozing="); ipw.println(mDozing); ipw.print("mDozingOnDown="); ipw.println(mDozingOnDown); ipw.print("mBouncerShowing="); ipw.println(mBouncerShowing); @@ -3552,31 +3399,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } @Override - public boolean closeUserSwitcherIfOpen() { - if (mKeyguardUserSwitcherController != null) { - return mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( - true /* animate */); - } - return false; - } - - private void updateUserSwitcherFlags() { - mKeyguardUserSwitcherEnabled = mResources.getBoolean( - com.android.internal.R.bool.config_keyguardUserSwitcher); - mKeyguardQsUserSwitchEnabled = - mKeyguardUserSwitcherEnabled - && mFeatureFlags.isEnabled(Flags.QS_USER_DETAIL_SHORTCUT); - } - - private void registerSettingsChangeListener() { - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED), - /* notifyForDescendants */ false, - mSettingsChangeObserver - ); - } - - @Override public void updateSystemUiStateFlags() { if (SysUiState.DEBUG) { Log.d(TAG, "Updating panel sysui state flags: fullyExpanded=" @@ -4261,13 +4083,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } } - private void onQsStateUpdated(boolean qsExpanded, boolean isStackScrollerOverscrolling) { - if (mKeyguardUserSwitcherController != null && qsExpanded - && !isStackScrollerOverscrolling) { - mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(true); - } - } - private void onQsClippingImmediatelyApplied(boolean clipStatusView, Rect lastQsClipBounds, int top, boolean qsFragmentCreated, boolean qsVisible) { if (qsFragmentCreated) { @@ -4383,44 +4198,12 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } @Override - public void onSmallestScreenWidthChanged() { - Trace.beginSection("onSmallestScreenWidthChanged"); - debugLog("onSmallestScreenWidthChanged"); - - // Can affect multi-user switcher visibility as it depends on screen size by default: - // it is enabled only for devices with large screens (see config_keyguardUserSwitcher) - boolean prevKeyguardUserSwitcherEnabled = mKeyguardUserSwitcherEnabled; - boolean prevKeyguardQsUserSwitchEnabled = mKeyguardQsUserSwitchEnabled; - updateUserSwitcherFlags(); - if (prevKeyguardUserSwitcherEnabled != mKeyguardUserSwitcherEnabled - || prevKeyguardQsUserSwitchEnabled != mKeyguardQsUserSwitchEnabled) { - reInflateViews(); - } - - Trace.endSection(); - } - - @Override public void onDensityOrFontScaleChanged() { debugLog("onDensityOrFontScaleChanged"); reInflateViews(); } } - private final class SettingsChangeObserver extends ContentObserver { - SettingsChangeObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - debugLog("onSettingsChanged"); - - // Can affect multi-user switcher visibility - reInflateViews(); - } - } - private final class StatusBarStateListener implements StateListener { @Override public void onStateChanged(int statusBarState) { @@ -4592,12 +4375,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mConfigurationListener.onThemeChanged(); mFalsingManager.addTapListener(mFalsingTapListener); mKeyguardIndicationController.init(); - registerSettingsChangeListener(); } @Override public void onViewDetachedFromWindow(View v) { - mContentResolver.unregisterContentObserver(mSettingsChangeObserver); mFragmentService.getFragmentHostManager(mView) .removeTagListener(QS.TAG, mQsController.getQsFragmentListener()); mStatusBarStateController.removeCallback(mStatusBarStateListener); @@ -4724,13 +4505,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } mKeyguardInteractor.setAlpha(alpha); - - if (mKeyguardQsUserSwitchController != null) { - mKeyguardQsUserSwitchController.setAlpha(alpha); - } - if (mKeyguardUserSwitcherController != null) { - mKeyguardUserSwitcherController.setAlpha(alpha); - } }; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index f2c39063c867..839d4596bb7c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -48,7 +48,6 @@ import com.android.systemui.flags.FeatureFlagsClassic; import com.android.systemui.flags.Flags; import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; -import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.model.Edge; import com.android.systemui.keyguard.shared.model.KeyguardState; @@ -367,9 +366,7 @@ public class NotificationShadeWindowViewController implements Dumpable { mTouchActive = true; mTouchCancelled = false; mDownEvent = ev; - if (MigrateClocksToBlueprint.isEnabled()) { - mService.userActivity(); - } + mService.userActivity(); } else if (ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { mTouchActive = false; @@ -443,8 +440,7 @@ public class NotificationShadeWindowViewController implements Dumpable { float x = ev.getRawX(); float y = ev.getRawY(); if (mStatusBarViewController.touchIsWithinView(x, y)) { - if (!(MigrateClocksToBlueprint.isEnabled() - && mPrimaryBouncerInteractor.isBouncerShowing())) { + if (!mPrimaryBouncerInteractor.isBouncerShowing()) { if (mStatusBarWindowStateController.windowIsShowing()) { mIsTrackingBarGesture = true; return logDownDispatch(ev, "sending touch to status bar", @@ -453,7 +449,7 @@ public class NotificationShadeWindowViewController implements Dumpable { return logDownDispatch(ev, "hidden or hiding", true); } } else { - mShadeLogger.d("NSWVC: bouncer not showing"); + mShadeLogger.d("NSWVC: bouncer showing"); } } else { mShadeLogger.d("NSWVC: touch not within view"); @@ -511,34 +507,24 @@ public class NotificationShadeWindowViewController implements Dumpable { && !bouncerShowing && !mStatusBarStateController.isDozing()) { if (mDragDownHelper.isDragDownEnabled()) { - if (MigrateClocksToBlueprint.isEnabled()) { - // When on lockscreen, if the touch originates at the top of the screen - // go directly to QS and not the shade - if (mStatusBarStateController.getState() == KEYGUARD - && mQuickSettingsController.shouldQuickSettingsIntercept( - ev.getX(), ev.getY(), 0)) { - mShadeLogger.d("NSWVC: QS intercepted"); - return true; - } + // When on lockscreen, if the touch originates at the top of the screen go + // directly to QS and not the shade + if (mStatusBarStateController.getState() == KEYGUARD + && mQuickSettingsController.shouldQuickSettingsIntercept( + ev.getX(), ev.getY(), 0)) { + mShadeLogger.d("NSWVC: QS intercepted"); + return true; } // This handles drag down over lockscreen boolean result = mDragDownHelper.onInterceptTouchEvent(ev); - if (MigrateClocksToBlueprint.isEnabled()) { - if (result) { - mLastInterceptWasDragDownHelper = true; - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mShadeLogger.d("NSWVC: drag down helper intercepted"); - } - } else if (didNotificationPanelInterceptEvent(ev)) { - return true; - } - } else { - if (result) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mShadeLogger.d("NSWVC: drag down helper intercepted"); - } + if (result) { + mLastInterceptWasDragDownHelper = true; + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mShadeLogger.d("NSWVC: drag down helper intercepted"); } + } else if (didNotificationPanelInterceptEvent(ev)) { + return true; } return result; } else { @@ -547,12 +533,10 @@ public class NotificationShadeWindowViewController implements Dumpable { return true; } } - } else if (MigrateClocksToBlueprint.isEnabled()) { + } else if (!bouncerShowing && didNotificationPanelInterceptEvent(ev)) { // This final check handles swipes on HUNs and when Pulsing - if (!bouncerShowing && didNotificationPanelInterceptEvent(ev)) { - mShadeLogger.d("NSWVC: intercepted for HUN/PULSING"); - return true; - } + mShadeLogger.d("NSWVC: intercepted for HUN/PULSING"); + return true; } return false; } @@ -562,9 +546,6 @@ public class NotificationShadeWindowViewController implements Dumpable { MotionEvent cancellation = MotionEvent.obtain(ev); cancellation.setAction(MotionEvent.ACTION_CANCEL); mStackScrollLayout.onInterceptTouchEvent(cancellation); - if (!MigrateClocksToBlueprint.isEnabled()) { - mShadeViewController.handleExternalInterceptTouch(cancellation); - } cancellation.recycle(); } @@ -574,22 +555,12 @@ public class NotificationShadeWindowViewController implements Dumpable { if (mStatusBarStateController.isDozing()) { handled = !mDozeServiceHost.isPulsing(); } - if (MigrateClocksToBlueprint.isEnabled()) { - if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) { - // we still want to finish our drag down gesture when locking the screen - handled |= mDragDownHelper.onTouchEvent(ev) || handled; - } - if (!handled && mShadeViewController.handleExternalTouch(ev)) { - return true; - } - } else { - if (mDragDownHelper.isDragDownEnabled() - || mDragDownHelper.isDraggingDown()) { - // we still want to finish our drag down gesture when locking the screen - return mDragDownHelper.onTouchEvent(ev) || handled; - } else { - return handled; - } + if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) { + // we still want to finish our drag down gesture when locking the screen + handled |= mDragDownHelper.onTouchEvent(ev) || handled; + } + if (!handled && mShadeViewController.handleExternalTouch(ev)) { + return true; } return handled; } @@ -673,14 +644,12 @@ public class NotificationShadeWindowViewController implements Dumpable { } private boolean didNotificationPanelInterceptEvent(MotionEvent ev) { - if (MigrateClocksToBlueprint.isEnabled()) { - // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need - // to also ask NotificationPanelViewController directly, in order to process swipe up - // events originating from notifications - if (mShadeViewController.handleExternalInterceptTouch(ev)) { - mShadeLogger.d("NSWVC: NPVC intercepted"); - return true; - } + // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need to + // also ask NotificationPanelViewController directly, in order to process swipe up events + // originating from notifications + if (mShadeViewController.handleExternalInterceptTouch(ev)) { + mShadeLogger.d("NSWVC: NPVC intercepted"); + return true; } return false; @@ -707,9 +676,7 @@ public class NotificationShadeWindowViewController implements Dumpable { if (!SceneContainerFlag.isEnabled()) { mAmbientState.setSwipingUp(false); } - if (MigrateClocksToBlueprint.isEnabled()) { - mDragDownHelper.stopDragging(); - } + mDragDownHelper.stopDragging(); } private void setBrightnessMirrorShowingForDepth(boolean showing) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index 207439e1f374..58111576574e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -21,7 +21,6 @@ import android.view.ViewGroup import android.view.WindowInsets import androidx.annotation.VisibleForTesting import androidx.constraintlayout.widget.ConstraintSet -import androidx.constraintlayout.widget.ConstraintSet.BOTTOM import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START @@ -32,7 +31,6 @@ import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.fragments.FragmentService -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.plugins.qs.QS @@ -275,7 +273,6 @@ constructor( constraintSet.clone(mView) setKeyguardStatusViewConstraints(constraintSet) setQsConstraints(constraintSet) - setNotificationsConstraints(constraintSet) setLargeScreenShadeHeaderConstraints(constraintSet) mView.applyConstraints(constraintSet) } @@ -288,21 +285,6 @@ constructor( } } - private fun setNotificationsConstraints(constraintSet: ConstraintSet) { - if (MigrateClocksToBlueprint.isEnabled) { - return - } - val startConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID - val nsslId = R.id.notification_stack_scroller - constraintSet.apply { - connect(nsslId, START, startConstraintId, START) - setMargin(nsslId, START, if (splitShadeEnabled) 0 else panelMarginHorizontal) - setMargin(nsslId, END, panelMarginHorizontal) - setMargin(nsslId, TOP, topMargin) - setMargin(nsslId, BOTTOM, notificationsBottomMargin) - } - } - private fun setQsConstraints(constraintSet: ConstraintSet) { val endConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID constraintSet.apply { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java index 13330553b2de..000a666bac0d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java @@ -21,7 +21,6 @@ import static androidx.constraintlayout.core.widgets.Optimizer.OPTIMIZATION_GRAP import android.app.Fragment; import android.content.Context; import android.content.res.Configuration; -import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; @@ -33,13 +32,10 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; -import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.plugins.qs.QS; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AboveShelfObserver; -import java.util.ArrayList; -import java.util.Comparator; import java.util.function.Consumer; /** @@ -50,11 +46,7 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout private View mQsFrame; private View mStackScroller; - private View mKeyguardStatusBar; - private final ArrayList<View> mDrawingOrderedChildren = new ArrayList<>(); - private final ArrayList<View> mLayoutDrawingOrder = new ArrayList<>(); - private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild); private Consumer<WindowInsets> mInsetsChangedListener = insets -> {}; private Consumer<QS> mQSFragmentAttachedListener = qs -> {}; private QS mQs; @@ -80,7 +72,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout protected void onFinishInflate() { super.onFinishInflate(); mQsFrame = findViewById(R.id.qs_frame); - mKeyguardStatusBar = findViewById(R.id.keyguard_header); } void setStackScroller(View stackScroller) { @@ -160,46 +151,11 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout } @Override - protected void dispatchDraw(Canvas canvas) { - mDrawingOrderedChildren.clear(); - mLayoutDrawingOrder.clear(); - if (mKeyguardStatusBar.getVisibility() == View.VISIBLE) { - mDrawingOrderedChildren.add(mKeyguardStatusBar); - mLayoutDrawingOrder.add(mKeyguardStatusBar); - } - if (mQsFrame.getVisibility() == View.VISIBLE) { - mDrawingOrderedChildren.add(mQsFrame); - mLayoutDrawingOrder.add(mQsFrame); - } - if (mStackScroller.getVisibility() == View.VISIBLE) { - mDrawingOrderedChildren.add(mStackScroller); - mLayoutDrawingOrder.add(mStackScroller); - } - - // Let's now find the order that the view has when drawing regularly by sorting - mLayoutDrawingOrder.sort(mIndexComparator); - super.dispatchDraw(canvas); - } - - @Override public boolean dispatchTouchEvent(MotionEvent ev) { return TouchLogger.logDispatchTouch("NotificationsQuickSettingsContainer", ev, super.dispatchTouchEvent(ev)); } - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (MigrateClocksToBlueprint.isEnabled()) { - return super.drawChild(canvas, child, drawingTime); - } - int layoutIndex = mLayoutDrawingOrder.indexOf(child); - if (layoutIndex >= 0) { - return super.drawChild(canvas, mDrawingOrderedChildren.get(layoutIndex), drawingTime); - } else { - return super.drawChild(canvas, child, drawingTime); - } - } - public void applyConstraints(ConstraintSet constraintSet) { constraintSet.applyTo(this); } diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java index 0df2299eb8dd..4fb43fdcfdae 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java @@ -68,7 +68,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.fragments.FragmentHostManager; -import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.media.controls.domain.pipeline.MediaDataManager; import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager; import com.android.systemui.plugins.FalsingManager; @@ -1828,16 +1827,6 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum "onQsIntercept: down action, QS partially expanded/collapsed"); return true; } - // TODO (b/265193930): remove dependency on NPVC - if (mPanelViewControllerLazy.get().isKeyguardShowing() - && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) { - // Dragging down on the lockscreen statusbar should prohibit other interactions - // immediately, otherwise we'll wait on the touchslop. This is to allow - // dragging down to expanded quick settings directly on the lockscreen. - if (!MigrateClocksToBlueprint.isEnabled()) { - mPanelView.getParent().requestDisallowInterceptTouchEvent(true); - } - } if (mExpansionAnimator != null) { mInitialHeightOnTouch = mExpansionHeight; mShadeLog.logMotionEvent(event, @@ -1879,9 +1868,6 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum && Math.abs(h) > Math.abs(x - mInitialTouchX) && shouldQuickSettingsIntercept( mInitialTouchX, mInitialTouchY, h)) { - if (!MigrateClocksToBlueprint.isEnabled()) { - mPanelView.getParent().requestDisallowInterceptTouchEvent(true); - } mShadeLog.onQsInterceptMoveQsTrackingEnabled(h); setTracking(true); traceQsJank(true, false); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt index d31868ca0217..61b9f0819f56 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt @@ -35,6 +35,8 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl import com.android.systemui.shade.display.ShadeDisplayPolicyModule @@ -216,6 +218,25 @@ object ShadeDisplayAwareModule { } @Provides + @SysUISingleton + fun provideShadeDialogContextInteractor( + impl: ShadeDialogContextInteractorImpl + ): ShadeDialogContextInteractor = impl + + @Provides + @IntoMap + @ClassKey(ShadeDialogContextInteractor::class) + fun provideShadeDialogContextInteractorCoreStartable( + impl: Provider<ShadeDialogContextInteractorImpl> + ): CoreStartable { + return if (ShadeWindowGoesAround.isEnabled) { + impl.get() + } else { + CoreStartable.NOP + } + } + + @Provides @IntoMap @ClassKey(ShadePrimaryDisplayCommand::class) fun provideShadePrimaryDisplayCommand( diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt index 53617d09fa1c..f65d3780b21e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt @@ -55,19 +55,12 @@ open class ShadeViewControllerEmptyImpl @Inject constructor() : override fun startExpandLatencyTracking() {} - override fun startBouncerPreHideAnimation() {} - override fun dozeTimeTick() {} override fun resetViews(animate: Boolean) {} override val barState: Int = 0 - @Deprecated("Only supported by very old devices that will not adopt scenes.") - override fun closeUserSwitcherIfOpen(): Boolean { - return false - } - override fun onBackPressed() {} @Deprecated("According to b/318376223, shade predictive back is not be supported.") diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeDialogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeDialogContextInteractor.kt new file mode 100644 index 000000000000..455370c726a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/FakeShadeDialogContextInteractor.kt @@ -0,0 +1,23 @@ +/* + * 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.shade.domain.interactor + +import android.content.Context + +/** Fake context repository that always returns the same context. */ +class FakeShadeDialogContextInteractor(override val context: Context) : + ShadeDialogContextInteractor diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractor.kt index 15ea2197e5ca..faf238cd6454 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractor.kt @@ -29,17 +29,6 @@ interface ShadeBackActionInteractor { /** Returns whether the shade can be collapsed. */ fun canBeCollapsed(): Boolean - /** - * Close the keyguard user switcher if it is open and capable of closing. - * - * Has no effect if user switcher isn't supported, if the user switcher is already closed, or if - * the user switcher uses "simple" mode. The simple user switcher cannot be closed. - * - * @return true if the keyguard user switcher was open, and is now closed - */ - @Deprecated("Only supported by very old devices that will not adopt scenes.") - fun closeUserSwitcherIfOpen(): Boolean - /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */ fun onBackPressed() diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt index f1513071de65..884cfc10678d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt @@ -49,11 +49,6 @@ constructor( return shadeInteractor.isAnyExpanded.value && !shadeInteractor.isUserInteracting.value } - @Deprecated("Only supported by very old devices that will not adopt scenes.") - override fun closeUserSwitcherIfOpen(): Boolean { - return false - } - override fun onBackPressed() { animateCollapseQs(false) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt new file mode 100644 index 000000000000..201dc0339a0a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt @@ -0,0 +1,97 @@ +/* + * 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.shade.domain.interactor + +import android.content.Context +import android.util.Log +import android.view.Display +import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL +import com.android.app.tracing.coroutines.launchTraced +import com.android.app.tracing.traceSection +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository +import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround +import javax.inject.Inject +import javax.inject.Provider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.filter + +/** Provides the correct context to show dialogs on the shade window, whenever it moves. */ +interface ShadeDialogContextInteractor { + /** Context usable to create dialogs on the notification shade display. */ + val context: Context +} + +@SysUISingleton +class ShadeDialogContextInteractorImpl +@Inject +constructor( + @Main private val defaultContext: Context, + private val displayWindowPropertyRepository: Provider<DisplayWindowPropertiesRepository>, + private val shadeDisplaysRepository: ShadeDisplaysRepository, + @Background private val bgScope: CoroutineScope, +) : CoreStartable, ShadeDialogContextInteractor { + + override fun start() { + if (ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()) return + bgScope.launchTraced(TAG) { + shadeDisplaysRepository.displayId + // No need for default display pre-warming. + .filter { it != Display.DEFAULT_DISPLAY } + .collectLatest { displayId -> + // Prewarms the context in the background every time the display changes. + // In this way, there will be no main thread delays when a dialog is shown. + getContextOrDefault(displayId) + } + } + } + + override val context: Context + get() { + if (!ShadeWindowGoesAround.isEnabled) { + return defaultContext + } + val displayId = shadeDisplaysRepository.displayId.value + return getContextOrDefault(displayId) + } + + private fun getContextOrDefault(displayId: Int): Context { + return try { + traceSection({ "Getting dialog context for displayId=$displayId" }) { + displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE).context + } + } catch (e: Exception) { + // This can happen if the display was disconnected in the meantime. + Log.e( + TAG, + "Couldn't get dialog context for displayId=$displayId. Returning default one", + e, + ) + defaultContext + } + } + + private companion object { + const val TAG = "ShadeDialogContextRepo" + const val DIALOG_WINDOW_TYPE = TYPE_STATUS_BAR_SUB_PANEL + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index a3f2c64f6909..f1765e775d65 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -79,11 +79,7 @@ interface ShadeInteractor : BaseShadeInteractor { * The fraction between [0..1] (i.e., percentage) of screen width to consider the threshold * between "top-left" and "top-right" for the purposes of dual-shade invocation. * - * When the dual-shade is not wide, this always returns 0.5 (the top edge is evenly split). On - * wide layouts however, a larger fraction is returned because only the area of the system - * status icons is considered top-right. - * - * Note that this fraction only determines the split between the absolute left and right + * Note that this fraction only determines the *split* between the absolute left and right * directions. In RTL layouts, the "top-start" edge will resolve to "top-right", and "top-end" * will resolve to "top-left". */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt index 987c01699f2f..f538d7446453 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractor.kt @@ -38,9 +38,6 @@ interface ShadeLockscreenInteractor { */ @Deprecated("Use ShadeInteractor instead") val isExpanded: Boolean - /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */ - fun startBouncerPreHideAnimation() - /** Called once every minute while dozing. */ fun dozeTimeTick() diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt index 2d7476c0433c..d712ece7f144 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt @@ -16,6 +16,7 @@ package com.android.systemui.shade.domain.interactor +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.model.KeyguardState @@ -27,7 +28,6 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext class ShadeLockscreenInteractorImpl @@ -54,10 +54,6 @@ constructor( override val isExpanded get() = shadeInteractor.isAnyExpanded.value - override fun startBouncerPreHideAnimation() { - // TODO("b/324280998") Implement replacement or delete - } - override fun dozeTimeTick() { // TODO("b/383591086") Implement replacement or delete } 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 c838c378965f..edf503d03f3e 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 @@ -76,10 +76,8 @@ interface ShadeModeInteractor { class ShadeModeInteractorImpl @Inject -constructor( - @Application applicationScope: CoroutineScope, - private val repository: ShadeRepository, -) : ShadeModeInteractor { +constructor(@Application applicationScope: CoroutineScope, repository: ShadeRepository) : + ShadeModeInteractor { override val isShadeLayoutWide: StateFlow<Boolean> = repository.isShadeLayoutWide @@ -92,15 +90,7 @@ constructor( initialValue = determineShadeMode(isShadeLayoutWide.value), ) - @FloatRange(from = 0.0, to = 1.0) - override fun getTopEdgeSplitFraction(): Float { - // Note: this implicitly relies on isShadeLayoutWide being hot (i.e. collected). This - // assumption allows us to query its value on demand (during swipe source detection) instead - // of running another infinite coroutine. - // TODO(b/338577208): Instead of being fixed at 0.8f, this should dynamically updated based - // on the position of system-status icons in the status bar. - return if (repository.isShadeLayoutWide.value) 0.8f else 0.5f - } + @FloatRange(from = 0.0, to = 1.0) override fun getTopEdgeSplitFraction(): Float = 0.5f private fun determineShadeMode(isShadeLayoutWide: Boolean): ShadeMode { return when { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index b2ca33a4aecf..a7ad46296e08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -44,13 +44,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor.Configuration; import com.android.internal.logging.UiEventLogger; -import com.android.keyguard.KeyguardClockSwitch; import com.android.systemui.DejankUtils; import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor; import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus; -import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -136,7 +134,6 @@ public class StatusBarStateControllerImpl implements private HistoricalState[] mHistoricalRecords = new HistoricalState[HISTORY_SIZE]; // These views are used by InteractionJankMonitor to get callback from HWUI. private View mView; - private KeyguardClockSwitch mClockSwitchView; /** * If any of the system bars is hidden. @@ -426,7 +423,6 @@ public class StatusBarStateControllerImpl implements if ((mView == null || !mView.isAttachedToWindow()) && (view != null && view.isAttachedToWindow())) { mView = view; - mClockSwitchView = view.findViewById(R.id.keyguard_clock_container); } mDozeAmountTarget = dozeAmount; if (animated) { @@ -511,16 +507,7 @@ public class StatusBarStateControllerImpl implements /** Returns the id of the currently rendering clock */ public String getClockId() { - if (MigrateClocksToBlueprint.isEnabled()) { - return mKeyguardClockInteractorLazy.get().getRenderedClockId(); - } - - if (mClockSwitchView == null) { - Log.e(TAG, "Clock container was missing"); - return KeyguardClockSwitch.MISSING_CLOCK_ID; - } - - return mClockSwitchView.getClockId(); + return mKeyguardClockInteractorLazy.get().getRenderedClockId(); } private void beginInteractionJankMonitor() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index 66af275bc702..a7dbb47bc609 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.chips.notification.ui.viewmodel import android.view.View +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor @@ -99,6 +100,17 @@ constructor( ) } + if (Flags.promoteNotificationsAutomatically()) { + // When we're promoting notifications automatically, the `when` time set on the + // notification will likely just be set to the current time, which would cause the chip + // to always show "now". We don't want early testers to get that experience since it's + // not what will happen at launch, so just don't show any time. + // TODO(b/364653005): Only ignore the `when` time if the notification was + // *automatically* promoted (as opposed to being legitimately promoted by the + // criteria). We'll need to track that status somehow. + return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener) + } + if (this.promotedContent.time == null) { return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipDateTimeView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipDateTimeView.kt new file mode 100644 index 000000000000..6ebeb84ac962 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipDateTimeView.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.chips.ui.view + +import android.content.Context +import android.content.res.Configuration +import android.util.AttributeSet +import android.widget.DateTimeView + +/** A [DateTimeView] for chips in the status bar. See also: [ChipTextView]. */ +class ChipDateTimeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + DateTimeView(context, attrs) { + private val textTruncationHelper = ChipTextTruncationHelper(this) + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + textTruncationHelper.onConfigurationChanged() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + // Evaluate how wide the text *wants* to be if it had unlimited space. This is needed so + // that [textTruncationHelper.shouldShowText] works correctly. + super.onMeasure(textTruncationHelper.unlimitedWidthMeasureSpec.specInt, heightMeasureSpec) + + if ( + textTruncationHelper.shouldShowText( + desiredTextWidthPx = measuredWidth, + widthMeasureSpec = SysuiMeasureSpec(widthMeasureSpec), + ) + ) { + // Show the text with the width spec specified by the helper + super.onMeasure(textTruncationHelper.widthMeasureSpec.specInt, heightMeasureSpec) + } else { + // Changing visibility ensures that the content description is not read aloud when the + // text isn't displayed. + visibility = GONE + setMeasuredDimension(0, 0) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelper.kt new file mode 100644 index 000000000000..52495eb55436 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextTruncationHelper.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.chips.ui.view + +import android.view.View +import android.view.View.MeasureSpec +import android.widget.TextView.resolveSize +import com.android.systemui.res.R + +/** + * Helper class to determine when a status bar chip's text should be hidden because it's too long. + */ +class ChipTextTruncationHelper(private val view: View) { + /** A measure spec for the status bar chip text with an unlimited width. */ + val unlimitedWidthMeasureSpec = + SysuiMeasureSpec(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)) + + /** The [MeasureSpec] that the view should actually use win [onMeasure]. */ + lateinit var widthMeasureSpec: SysuiMeasureSpec + + private var maxWidth: Int = 0 + set(value) { + field = value + maximumWidthMeasureSpec = + SysuiMeasureSpec(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST)) + } + + /** A measure spec for the status bar chip text with the correct maximum width. */ + private lateinit var maximumWidthMeasureSpec: SysuiMeasureSpec + + init { + maxWidth = fetchMaxWidth() + } + + fun onConfigurationChanged() { + maxWidth = fetchMaxWidth() + } + + /** + * Returns true if this view should show the text because there's enough room for a substantial + * amount of text, and returns false if this view should hide the text because the text is much + * too long. + * + * @param desiredTextWidthPx should be calculated by having the view measure itself with + * [unlimitedWidthMeasureSpec] and then sending its `measuredWidth` to this method. (This + * class can't compute [desiredTextWidthPx] directly because [View.onMeasure] can only be + * called by the view itself.) + * @param widthMeasureSpec the view's current and unmodified width spec + */ + fun shouldShowText(desiredTextWidthPx: Int, widthMeasureSpec: SysuiMeasureSpec): Boolean { + // Evaluate how wide the text *can* be based on: + // #1: The maximum width encoded by [maxWidth] + val maxWidthBasedOnDimension = + resolveSize(desiredTextWidthPx, maximumWidthMeasureSpec.specInt) + // #2: The width the view is allowed to take up (If there's 2 chips, the second chip likely + // has < [maxWidth] room available) + val maxWidthBasedOnViewSpaceAvailable = + resolveSize(desiredTextWidthPx, widthMeasureSpec.specInt) + + val enforcedTextWidth: Int + if (maxWidthBasedOnViewSpaceAvailable < maxWidthBasedOnDimension) { + // View space available takes priority + this.widthMeasureSpec = widthMeasureSpec + enforcedTextWidth = maxWidthBasedOnViewSpaceAvailable + } else { + // Enforce the maximum width + this.widthMeasureSpec = maximumWidthMeasureSpec + enforcedTextWidth = maxWidthBasedOnDimension + } + + // Only show the text if at least 50% of it can show. (Assume that if < 50% of the text will + // be visible, the text will be more confusing than helpful.) + return desiredTextWidthPx <= enforcedTextWidth * 2 + } + + private fun fetchMaxWidth() = + view.context.resources.getDimensionPixelSize(R.dimen.ongoing_activity_chip_max_text_width) +} + +/** A typed class for [MeasureSpec] ints. */ +data class SysuiMeasureSpec(val specInt: Int) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextView.kt new file mode 100644 index 000000000000..3bcc9c1ac650 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/ChipTextView.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.chips.ui.view + +import android.content.Context +import android.content.res.Configuration +import android.util.AttributeSet +import android.widget.TextView + +/** A [TextView] for chips in the status bar. See also: [ChipDateTimeView]. */ +class ChipTextView +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : + TextView(context, attrs, defStyle) { + private val textTruncationHelper = ChipTextTruncationHelper(this) + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + textTruncationHelper.onConfigurationChanged() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + // Evaluate how wide the text *wants* to be if it had unlimited space. This is needed so + // that [textTruncationHelper.shouldShowText] works correctly. + super.onMeasure(textTruncationHelper.unlimitedWidthMeasureSpec.specInt, heightMeasureSpec) + + if ( + textTruncationHelper.shouldShowText( + desiredTextWidthPx = measuredWidth, + widthMeasureSpec = SysuiMeasureSpec(widthMeasureSpec), + ) + ) { + // Show the text with the width spec specified by the helper + super.onMeasure(textTruncationHelper.widthMeasureSpec.specInt, heightMeasureSpec) + } else { + // Changing visibility ensures that the content description is not read aloud when the + // text isn't displayed. + visibility = GONE + setMeasuredDimension(0, 0) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandParser.kt b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandParser.kt index de369c35345c..4289dab081b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandParser.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandParser.kt @@ -74,7 +74,8 @@ class CommandParser { */ fun parse(args: List<String>): Boolean { if (args.isEmpty()) { - return false + // An empty args list might be valid here if there are no required inputs + return validateRequiredParams() } val iterator = args.listIterator() @@ -268,11 +269,7 @@ class CommandParser { _subCommands.add(new) } - internal fun flag( - longName: String, - shortName: String? = null, - description: String = "", - ): Flag { + internal fun flag(longName: String, shortName: String? = null, description: String = ""): Flag { checkCliNames(shortName, longName)?.let { throw IllegalArgumentException("Detected reused flag name ($it)") } @@ -305,9 +302,7 @@ class CommandParser { return param } - internal fun <T : ParseableCommand> subCommand( - command: T, - ): OptionalSubCommand<T> { + internal fun <T : ParseableCommand> subCommand(command: T): OptionalSubCommand<T> { checkCliNames(null, command.name)?.let { throw IllegalArgumentException("Cannot re-use name for subcommand ($it)") } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index 7df7ef187e26..254b792f8152 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -63,6 +63,7 @@ import com.android.systemui.statusbar.phone.ui.StatusBarIconController; import com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl; import com.android.systemui.statusbar.phone.ui.StatusBarIconList; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.wm.shell.shared.ShellTransitions; import dagger.Binds; import dagger.Lazy; @@ -214,8 +215,8 @@ public interface CentralSurfacesDependenciesModule { @Provides @SysUISingleton static ActivityTransitionAnimator provideActivityTransitionAnimator( - @Main Executor mainExecutor) { - return new ActivityTransitionAnimator(mainExecutor); + @Main Executor mainExecutor, ShellTransitions shellTransitions) { + return new ActivityTransitionAnimator(mainExecutor, shellTransitions); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt new file mode 100644 index 000000000000..9f523fc845ab --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.chips.notification.shared + +import com.android.systemui.Flags +import com.android.systemui.flags.FlagToken +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the status bar popup chips flag state. */ +@Suppress("NOTHING_TO_INLINE") +object StatusBarPopupChips { + /** The aconfig flag name */ + const val FLAG_NAME = Flags.FLAG_STATUS_BAR_POPUP_CHIPS + + /** A token used for dependency declaration */ + val token: FlagToken + get() = FlagToken(FLAG_NAME, isEnabled) + + /** Is the refactor enabled */ + @JvmStatic + inline val isEnabled + get() = Flags.statusBarPopupChips() + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is not enabled to ensure that the refactor author catches issues in testing. + * Caution!! Using this check incorrectly will cause crashes in nextfood builds! + */ + @JvmStatic + inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt new file mode 100644 index 000000000000..1663aebd7287 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.shared.model + +import com.android.systemui.common.shared.model.Icon + +/** + * Ids used to track different types of popup chips. Will be used to ensure only one chip is + * displaying its popup at a time. + */ +sealed class PopupChipId(val value: String) { + data object MediaControls : PopupChipId("MediaControls") +} + +/** Model for individual status bar popup chips. */ +sealed class PopupChipModel { + abstract val logName: String + abstract val chipId: PopupChipId + + data class Hidden(override val chipId: PopupChipId, val shouldAnimate: Boolean = true) : + PopupChipModel() { + override val logName = "Hidden(id=$chipId, anim=$shouldAnimate)" + } + + data class Shown( + override val chipId: PopupChipId, + val icon: Icon, + val chipText: String, + val isToggled: Boolean = false, + val onToggle: () -> Unit, + val onIconPressed: () -> Unit, + ) : PopupChipModel() { + override val logName = "Shown(id=$chipId, toggled=$isToggled)" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt new file mode 100644 index 000000000000..5712be30ccd6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel + +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel +import kotlinx.coroutines.flow.StateFlow + +/** + * Interface for a view model that knows the display requirements for a single type of status bar + * popup chip. + */ +interface StatusBarPopupChipViewModel { + /** A flow modeling the popup chip that should be shown (or not shown). */ + val chip: StateFlow<PopupChipModel> +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt new file mode 100644 index 000000000000..b390f29b166c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +/** + * View model deciding which system process chips to show in the status bar. Emits a list of + * PopupChipModels. + */ +@SysUISingleton +class StatusBarPopupChipsViewModel @Inject constructor(@Background scope: CoroutineScope) { + private data class PopupChipBundle( + val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControls) + ) + + private val incomingPopupChipBundle: Flow<PopupChipBundle?> = + flowOf(null).stateIn(scope, SharingStarted.Lazily, PopupChipBundle()) + + val popupChips: Flow<List<PopupChipModel>> = + incomingPopupChipBundle + .map { _ -> listOf(null).filterIsInstance<PopupChipModel.Shown>() } + .stateIn(scope, SharingStarted.Lazily, emptyList()) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 80e8f55b897a..d83acf34ca99 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.inflation; import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; @@ -186,6 +187,9 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC); if (AsyncHybridViewInflation.isEnabled()) { params.markContentViewsFreeable(FLAG_CONTENT_VIEW_SINGLE_LINE); + if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { + params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE); + } } mRowContentBindStage.requestRebind(entry, null); } @@ -256,10 +260,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED); params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); params.setUseMinimized(isMinimized); - // TODO b/358403414: use the different types of redaction - boolean needsRedaction = inflaterParams.getRedactionType() != REDACTION_TYPE_NONE; + int redactionType = inflaterParams.getRedactionType(); - if (needsRedaction) { + params.setRedactionType(redactionType); + if (redactionType != REDACTION_TYPE_NONE) { params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC); } else { params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC); @@ -276,8 +280,8 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { } if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { - - if (inflaterParams.isChildInGroup() && needsRedaction) { + if (inflaterParams.isChildInGroup() + && redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE); } else { params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE); 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 8a1371f1c415..aa010cf63d5b 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 @@ -62,6 +62,7 @@ import com.android.systemui.statusbar.notification.data.NotificationDataLayerMod import com.android.systemui.statusbar.notification.domain.NotificationDomainLayerModule; import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor; import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModelModule; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.icon.ConversationIconManager; import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.init.NotificationsController; @@ -78,8 +79,7 @@ import com.android.systemui.statusbar.notification.logging.NotificationPanelLogg import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl; import com.android.systemui.statusbar.notification.logging.dagger.NotificationsLogModule; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor; -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger; -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProvider; +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractorImpl; import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl; @@ -92,7 +92,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModesCleanupStartable; import dagger.Binds; @@ -105,8 +104,6 @@ import kotlin.coroutines.CoroutineContext; import kotlinx.coroutines.CoroutineScope; -import java.util.Optional; - import javax.inject.Provider; /** @@ -315,21 +312,17 @@ public interface NotificationsModule { @ClassKey(ZenModesCleanupStartable.class) CoreStartable bindsZenModesCleanup(ZenModesCleanupStartable zenModesCleanup); - /** - * Provides {@link - * com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor} if - * one of the relevant feature flags is enabled. - */ + /** Provides the default implementation of {@link PromotedNotificationContentExtractor} if at + * least one of the relevant feature flags is enabled, or an implementation that always returns + * null if none are enabled. */ @Provides @SysUISingleton - static Optional<PromotedNotificationContentExtractor> - providePromotedNotificationContentExtractor( - PromotedNotificationsProvider provider, Context context, - PromotedNotificationLogger logger) { + static PromotedNotificationContentExtractor providesPromotedNotificationContentExtractor( + Provider<PromotedNotificationContentExtractorImpl> implProvider) { if (PromotedNotificationContentModel.featureFlagEnabled()) { - return Optional.of(new PromotedNotificationContentExtractor(provider, context, logger)); + return implProvider.get(); } else { - return Optional.empty(); + return (entry, recoveredBuilder) -> null; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java index 6756077e5444..d02e17cab534 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java @@ -1299,7 +1299,6 @@ public class HeadsUpManagerImpl } private NotificationEntry requireEntry() { - /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode(); return Objects.requireNonNull(mEntry); } 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 863c665eb4f5..4e9e3336b86f 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 @@ -34,15 +34,22 @@ import com.android.systemui.statusbar.notification.promoted.shared.model.Promote import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When import javax.inject.Inject +interface PromotedNotificationContentExtractor { + fun extractContent( + entry: NotificationEntry, + recoveredBuilder: Notification.Builder, + ): PromotedNotificationContentModel? +} + @SysUISingleton -class PromotedNotificationContentExtractor +class PromotedNotificationContentExtractorImpl @Inject constructor( private val promotedNotificationsProvider: PromotedNotificationsProvider, @ShadeDisplayAware private val context: Context, private val logger: PromotedNotificationLogger, -) { - fun extractContent( +) : PromotedNotificationContentExtractor { + override fun extractContent( entry: NotificationEntry, recoveredBuilder: Notification.Builder, ): PromotedNotificationContentModel? { @@ -169,5 +176,5 @@ private fun CallStyle.extractContent(contentBuilder: PromotedNotificationContent private fun ProgressStyle.extractContent(contentBuilder: PromotedNotificationContentModel.Builder) { // TODO: Create NotificationProgressModel.toSkeleton, or something similar. - contentBuilder.progress = createProgressModel(0xffffffff.toInt(), 0x00000000) + contentBuilder.progress = createProgressModel(0xffffffff.toInt(), 0xff000000.toInt()) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt index 13ad1413e89d..a43f8dbc1b5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.promoted import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel.ERROR import com.android.systemui.log.core.LogLevel.INFO -import com.android.systemui.log.dagger.NotificationLog import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel @@ -27,7 +26,7 @@ import javax.inject.Inject class PromotedNotificationLogger @Inject -constructor(@NotificationLog private val buffer: LogBuffer) { +constructor(@PromotedNotificationLog private val buffer: LogBuffer) { fun logExtractionSkipped(entry: NotificationEntry, reason: String) { buffer.log( EXTRACTION_TAG, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt new file mode 100644 index 000000000000..0f21514fcc94 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +@SysUISingleton +class AODPromotedNotificationInteractor +@Inject +constructor(activeNotificationsInteractor: ActiveNotificationsInteractor) { + val content: Flow<PromotedNotificationContentModel?> = + activeNotificationsInteractor.topLevelRepresentativeNotifications.map { notifs -> + notifs.firstNotNullOfOrNull { it.promotedContent } + } +} 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 fe2dabe1ba8a..74809fd8622f 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 @@ -28,7 +28,7 @@ import com.android.systemui.statusbar.notification.promoted.PromotedNotification * like the skeleton view on AOD or the status bar chip. */ data class PromotedNotificationContentModel( - val key: String, + val identity: Identity, // for all styles: val skeletonSmallIcon: Icon?, // TODO(b/377568176): Make into an IconModel. @@ -82,7 +82,7 @@ data class PromotedNotificationContentModel( fun build() = PromotedNotificationContentModel( - key = key, + identity = Identity(key, style), skeletonSmallIcon = skeletonSmallIcon, appName = appName, subText = subText, @@ -103,6 +103,8 @@ data class PromotedNotificationContentModel( ) } + data class Identity(val key: String, val style: Style) + /** The timestamp associated with a notification, along with the mode used to display it. */ data class When(val time: Long, val mode: Mode) { /** The mode used to display a notification's `when` value. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt new file mode 100644 index 000000000000..adfa6a10814d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Identity +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map + +@SysUISingleton +class AODPromotedNotificationViewModel +@Inject +constructor(interactor: AODPromotedNotificationInteractor) { + private val content: Flow<PromotedNotificationContentModel?> = interactor.content + private val identity: Flow<Identity?> = content.mapNonNullsKeepingNulls { it.identity } + + val notification: Flow<PromotedNotificationViewModel?> = + identity.distinctUntilChanged().mapNonNullsKeepingNulls { identity -> + val updates = interactor.content.filterNotNull().filter { it.identity == identity } + PromotedNotificationViewModel(identity, updates) + } +} + +private fun <T, R> Flow<T?>.mapNonNullsKeepingNulls(block: (T) -> R): Flow<R?> = map { + it?.let(block) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/PromotedNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/PromotedNotificationViewModel.kt new file mode 100644 index 000000000000..f265e0ff33f8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/PromotedNotificationViewModel.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.ui.viewmodel + +import android.graphics.drawable.Icon +import com.android.internal.widget.NotificationProgressModel +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 +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class PromotedNotificationViewModel( + identity: PromotedNotificationContentModel.Identity, + content: Flow<PromotedNotificationContentModel>, +) { + // for all styles: + + val key: String = identity.key + val style: Style = identity.style + + val skeletonSmallIcon: Flow<Icon?> = content.map { it.skeletonSmallIcon } + val appName: Flow<CharSequence?> = content.map { it.appName } + val subText: Flow<CharSequence?> = content.map { it.subText } + + private val time: Flow<When?> = content.map { it.time } + val whenTime: Flow<Long?> = time.map { it?.time } + val whenMode: Flow<When.Mode?> = time.map { it?.mode } + + val lastAudiblyAlertedMs: Flow<Long> = content.map { it.lastAudiblyAlertedMs } + val profileBadgeResId: Flow<Int?> = content.map { it.profileBadgeResId } + val title: Flow<CharSequence?> = content.map { it.title } + val text: Flow<CharSequence?> = content.map { it.text } + val skeletonLargeIcon: Flow<Icon?> = content.map { it.skeletonLargeIcon } + + // for CallStyle: + val personIcon: Flow<Icon?> = content.map { it.personIcon } + val personName: Flow<CharSequence?> = content.map { it.personName } + val verificationIcon: Flow<Icon?> = content.map { it.verificationIcon } + val verificationText: Flow<CharSequence?> = content.map { it.verificationText } + + // for ProgressStyle: + val progress: Flow<NotificationProgressModel?> = content.map { it.progress } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 6e05e8e8b80e..70e27a981b49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; @@ -25,6 +26,7 @@ import static com.android.systemui.statusbar.notification.row.NotificationConten import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; +import android.app.Notification.MessagingStyle; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; @@ -161,9 +163,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder entry, mConversationProcessor, row, - bindParams.isMinimized, - bindParams.usesIncreasedHeight, - bindParams.usesIncreasedHeadsUpHeight, + bindParams, callback, mRemoteInputManager.getRemoteViewsOnClickHandler(), /* isMediaFlagEnabled = */ mIsMediaInQS, @@ -187,13 +187,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder boolean inflateSynchronously, @InflationFlag int reInflateFlags, Notification.Builder builder, + Context systemUiContext, Context packageContext, SmartReplyStateInflater smartRepliesInflater) { InflationProgress result = createRemoteViews(reInflateFlags, builder, - bindParams.isMinimized, - bindParams.usesIncreasedHeight, - bindParams.usesIncreasedHeadsUpHeight, + bindParams, + systemUiContext, packageContext, row, mNotifLayoutInflaterFactoryProvider, @@ -203,18 +203,20 @@ public class NotificationContentInflater implements NotificationRowContentBinder result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(), packageContext, row.getExistingSmartReplyState(), smartRepliesInflater, mLogger); boolean isConversation = entry.getRanking().isConversation(); + Notification.MessagingStyle messagingStyle = null; + if (isConversation && (AsyncHybridViewInflation.isEnabled() + || LockscreenOtpRedaction.isSingleLineViewEnabled())) { + messagingStyle = mConversationProcessor + .processNotification(entry, builder, mLogger); + } if (AsyncHybridViewInflation.isEnabled()) { - Notification.MessagingStyle messagingStyle = null; - if (isConversation) { - messagingStyle = mConversationProcessor - .processNotification(entry, builder, mLogger); - } SingleLineViewModel viewModel = SingleLineViewInflater .inflateSingleLineViewModel( entry.getSbn().getNotification(), messagingStyle, builder, - row.getContext() + row.getContext(), + false ); // If the messagingStyle is null, we want to inflate the normal view isConversation = viewModel.isConversation(); @@ -228,11 +230,22 @@ public class NotificationContentInflater implements NotificationRowContentBinder mLogger ); } - if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { - result.mPublicInflatedSingleLineViewModel = - SingleLineViewInflater.inflateRedactedSingleLineViewModel(row.getContext(), - isConversation); + if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + result.mPublicInflatedSingleLineViewModel = + SingleLineViewInflater.inflateSingleLineViewModel( + entry.getSbn().getNotification(), + messagingStyle, + builder, + row.getContext(), + true); + } else { + result.mPublicInflatedSingleLineViewModel = + SingleLineViewInflater.inflateRedactedSingleLineViewModel( + row.getContext(), + isConversation + ); + } result.mPublicInflatedSingleLineView = SingleLineViewInflater.inflatePublicSingleLineView( isConversation, @@ -411,8 +424,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder } private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags, - Notification.Builder builder, boolean isMinimized, boolean usesIncreasedHeight, - boolean usesIncreasedHeadsUpHeight, Context packageContext, + Notification.Builder builder, BindParams bindParams, Context systemUiContext, + Context packageContext, ExpandableNotificationRow row, NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider, HeadsUpStyleProvider headsUpStyleProvider, @@ -423,13 +436,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) { logger.logAsyncTaskProgress(entryForLogging, "creating contracted remote view"); - result.newContentView = createContentView(builder, isMinimized, - usesIncreasedHeight); + result.newContentView = createContentView(builder, bindParams.isMinimized, + bindParams.usesIncreasedHeight); } if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) { logger.logAsyncTaskProgress(entryForLogging, "creating expanded remote view"); - result.newExpandedView = createExpandedView(builder, isMinimized); + result.newExpandedView = createExpandedView(builder, bindParams.isMinimized); } if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) { @@ -439,13 +452,20 @@ public class NotificationContentInflater implements NotificationRowContentBinder result.newHeadsUpView = builder.createCompactHeadsUpContentView(); } else { result.newHeadsUpView = builder.createHeadsUpContentView( - usesIncreasedHeadsUpHeight); + bindParams.usesIncreasedHeadsUpHeight); } } if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) { logger.logAsyncTaskProgress(entryForLogging, "creating public remote view"); - result.newPublicView = builder.makePublicContentView(isMinimized); + if (LockscreenOtpRedaction.isEnabled() + && bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + result.newPublicView = createSensitiveContentMessageNotification( + row.getEntry().getSbn().getNotification(), builder.getStyle(), + systemUiContext, packageContext).createContentView(true); + } else { + result.newPublicView = builder.makePublicContentView(bindParams.isMinimized); + } } if (AsyncGroupHeaderViewInflation.isEnabled()) { @@ -473,6 +493,42 @@ public class NotificationContentInflater implements NotificationRowContentBinder }); } + private static Notification.Builder createSensitiveContentMessageNotification( + Notification original, + Notification.Style originalStyle, + Context systemUiContext, + Context packageContext) { + Notification.Builder redacted = + new Notification.Builder(packageContext, original.getChannelId()); + redacted.setContentTitle(original.extras.getCharSequence(Notification.EXTRA_TITLE)); + CharSequence redactedMessage = systemUiContext.getString( + R.string.redacted_notification_single_line_text + ); + + if (originalStyle instanceof MessagingStyle oldStyle) { + MessagingStyle newStyle = new MessagingStyle(oldStyle.getUser()); + newStyle.setConversationTitle(oldStyle.getConversationTitle()); + newStyle.setGroupConversation(false); + newStyle.setConversationType(oldStyle.getConversationType()); + newStyle.setShortcutIcon(oldStyle.getShortcutIcon()); + newStyle.setBuilder(redacted); + MessagingStyle.Message latestMessage = + MessagingStyle.findLatestIncomingMessage(oldStyle.getMessages()); + if (latestMessage != null) { + MessagingStyle.Message newMessage = new MessagingStyle.Message(redactedMessage, + latestMessage.getTimestamp(), latestMessage.getSenderPerson()); + newStyle.addMessage(newMessage); + } + redacted.setStyle(newStyle); + } else { + redacted.setContentText(redactedMessage); + } + redacted.setLargeIcon(original.getLargeIcon()); + redacted.setSmallIcon(original.getSmallIcon()); + return redacted; + } + + private static void setNotifsViewsInflaterFactory(InflationProgress result, ExpandableNotificationRow row, NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) { @@ -921,7 +977,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder logger.logAsyncTaskProgress(entry, "finishing"); if (PromotedNotificationContentModel.featureFlagEnabled()) { - entry.setPromotedNotificationContentModel(result.mExtractedPromotedNotificationContent); + entry.setPromotedNotificationContentModel(result.mPromotedContent); } boolean setRepliesAndActions = true; @@ -1118,10 +1174,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder private final NotificationEntry mEntry; private final Context mContext; private final boolean mInflateSynchronously; - private final boolean mIsMinimized; - private final boolean mUsesIncreasedHeight; + private final BindParams mBindParams; private final InflationCallback mCallback; - private final boolean mUsesIncreasedHeadsUpHeight; private final @InflationFlag int mReInflateFlags; private final NotifRemoteViewCache mRemoteViewCache; private final Executor mInflationExecutor; @@ -1145,9 +1199,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder NotificationEntry entry, ConversationNotificationProcessor conversationProcessor, ExpandableNotificationRow row, - boolean isMinimized, - boolean usesIncreasedHeight, - boolean usesIncreasedHeadsUpHeight, + BindParams bindParams, InflationCallback callback, RemoteViews.InteractionHandler remoteViewClickHandler, boolean isMediaFlagEnabled, @@ -1164,9 +1216,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder mRemoteViewCache = cache; mSmartRepliesInflater = smartRepliesInflater; mContext = mRow.getContext(); - mIsMinimized = isMinimized; - mUsesIncreasedHeight = usesIncreasedHeight; - mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight; + mBindParams = bindParams; mRemoteViewClickHandler = remoteViewClickHandler; mCallback = callback; mConversationProcessor = conversationProcessor; @@ -1236,8 +1286,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder mEntry, recoveredBuilder, mLogger); } InflationProgress inflationProgress = createRemoteViews(mReInflateFlags, - recoveredBuilder, mIsMinimized, mUsesIncreasedHeight, - mUsesIncreasedHeadsUpHeight, packageContext, mRow, + recoveredBuilder, mBindParams, mContext, packageContext, mRow, mNotifLayoutInflaterFactoryProvider, mHeadsUpStyleProvider, mLogger); mLogger.logAsyncTaskProgress(mEntry, @@ -1264,7 +1313,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder mEntry.getSbn().getNotification(), messagingStyle, recoveredBuilder, - mContext + mContext, + false ); result.mInflatedSingleLineView = SingleLineViewInflater.inflatePrivateSingleLineView( @@ -1277,9 +1327,22 @@ public class NotificationContentInflater implements NotificationRowContentBinder } if (LockscreenOtpRedaction.isSingleLineViewEnabled()) { - result.mPublicInflatedSingleLineViewModel = - SingleLineViewInflater.inflateRedactedSingleLineViewModel(mContext, - isConversation); + if (mBindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + result.mPublicInflatedSingleLineViewModel = + SingleLineViewInflater.inflateSingleLineViewModel( + mEntry.getSbn().getNotification(), + messagingStyle, + recoveredBuilder, + mContext, + true + ); + } else { + result.mPublicInflatedSingleLineViewModel = + SingleLineViewInflater.inflateRedactedSingleLineViewModel( + mContext, + isConversation + ); + } result.mPublicInflatedSingleLineView = SingleLineViewInflater.inflatePublicSingleLineView( isConversation, @@ -1292,10 +1355,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder if (PromotedNotificationContentModel.featureFlagEnabled()) { mLogger.logAsyncTaskProgress(mEntry, "extracting promoted notification content"); - result.mExtractedPromotedNotificationContent = mPromotedNotificationContentExtractor - .extractContent(mEntry, recoveredBuilder); + final PromotedNotificationContentModel promotedContent = + mPromotedNotificationContentExtractor.extractContent(mEntry, + recoveredBuilder); mLogger.logAsyncTaskProgress(mEntry, "extracted promoted notification content: " - + result.mExtractedPromotedNotificationContent); + + promotedContent); + + result.mPromotedContent = promotedContent; } mLogger.logAsyncTaskProgress(mEntry, @@ -1317,7 +1383,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder mCancellationSignal = apply( mInflationExecutor, mInflateSynchronously, - mIsMinimized, + mBindParams.isMinimized, result, mReInflateFlags, mRemoteViewCache, @@ -1399,7 +1465,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder @VisibleForTesting static class InflationProgress { - PromotedNotificationContentModel mExtractedPromotedNotificationContent; + PromotedNotificationContentModel mPromotedContent; private RemoteViews newContentView; private RemoteViews newHeadsUpView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java index 07384afe2d2e..1cef8791e0ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -141,20 +143,33 @@ public interface NotificationRowContentBinder { */ class BindParams { + public BindParams(boolean minimized, boolean increasedHeight, + boolean increasedHeadsUpHeight, int redaction) { + isMinimized = minimized; + usesIncreasedHeight = increasedHeight; + usesIncreasedHeadsUpHeight = increasedHeadsUpHeight; + redactionType = redaction; + } + /** * Bind a minimized version of the content views. */ - public boolean isMinimized; + public final boolean isMinimized; /** * Use increased height when binding contracted view. */ - public boolean usesIncreasedHeight; + public final boolean usesIncreasedHeight; /** * Use increased height when binding heads up views. */ - public boolean usesIncreasedHeadsUpHeight; + public final boolean usesIncreasedHeadsUpHeight; + + /** + * Controls the type of public view to show, if a public view is requested + */ + public final @RedactionType int redactionType; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt index c7d80e9d03ce..c619b17f1ad8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt @@ -16,8 +16,8 @@ package com.android.systemui.statusbar.notification.row import android.annotation.SuppressLint -import android.app.Flags import android.app.Notification +import android.app.Notification.MessagingStyle import android.content.Context import android.content.ContextWrapper import android.content.pm.ApplicationInfo @@ -43,6 +43,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.NotifInflation import com.android.systemui.res.R import com.android.systemui.statusbar.InflationTask +import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.InflationException @@ -143,9 +144,7 @@ constructor( entry, conversationProcessor, row, - bindParams.isMinimized, - bindParams.usesIncreasedHeight, - bindParams.usesIncreasedHeadsUpHeight, + bindParams, callback, remoteInputManager.remoteViewsOnClickHandler, /* isMediaFlagEnabled = */ smartReplyStateInflater, @@ -179,10 +178,8 @@ constructor( reInflateFlags = reInflateFlags, entry = entry, builder = builder, - isMinimized = bindParams.isMinimized, - usesIncreasedHeight = bindParams.usesIncreasedHeight, - usesIncreasedHeadsUpHeight = bindParams.usesIncreasedHeadsUpHeight, - systemUIContext = systemUIContext, + bindParams, + systemUiContext = systemUIContext, packageContext = packageContext, row = row, notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, @@ -371,9 +368,7 @@ constructor( private val entry: NotificationEntry, private val conversationProcessor: ConversationNotificationProcessor, private val row: ExpandableNotificationRow, - private val isMinimized: Boolean, - private val usesIncreasedHeight: Boolean, - private val usesIncreasedHeadsUpHeight: Boolean, + private val bindParams: BindParams, private val callback: InflationCallback?, private val remoteViewClickHandler: InteractionHandler?, private val smartRepliesInflater: SmartReplyStateInflater, @@ -441,10 +436,8 @@ constructor( reInflateFlags = reInflateFlags, entry = entry, builder = recoveredBuilder, - isMinimized = isMinimized, - usesIncreasedHeight = usesIncreasedHeight, - usesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight, - systemUIContext = context, + bindParams = bindParams, + systemUiContext = context, packageContext = packageContext, row = row, notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, @@ -514,7 +507,7 @@ constructor( apply( inflationExecutor, inflateSynchronously, - isMinimized, + bindParams.isMinimized, progress, reInflateFlags, remoteViewCache, @@ -591,7 +584,7 @@ constructor( @VisibleForTesting val packageContext: Context, val remoteViews: NewRemoteViews, val contentModel: NotificationContentModel, - val extractedPromotedNotificationContentModel: PromotedNotificationContentModel?, + val promotedContent: PromotedNotificationContentModel?, ) { var inflatedContentView: View? = null @@ -671,10 +664,8 @@ constructor( @InflationFlag reInflateFlags: Int, entry: NotificationEntry, builder: Notification.Builder, - isMinimized: Boolean, - usesIncreasedHeight: Boolean, - usesIncreasedHeadsUpHeight: Boolean, - systemUIContext: Context, + bindParams: BindParams, + systemUiContext: Context, packageContext: Context, row: ExpandableNotificationRow, notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, @@ -683,16 +674,15 @@ constructor( promotedNotificationContentExtractor: PromotedNotificationContentExtractor, logger: NotificationRowContentBinderLogger, ): InflationProgress { - val promoted = + val promotedContent = if (PromotedNotificationContentModel.featureFlagEnabled()) { logger.logAsyncTaskProgress(entry, "extracting promoted notification content") - val extracted = - promotedNotificationContentExtractor.extractContent(entry, builder) - logger.logAsyncTaskProgress( - entry, - "extracted promoted notification content: {extracted}", - ) - extracted + promotedNotificationContentExtractor.extractContent(entry, builder).also { + logger.logAsyncTaskProgress( + entry, + "extracted promoted notification content: $it", + ) + } } else { null } @@ -707,9 +697,10 @@ constructor( createRemoteViews( reInflateFlags = reInflateFlags, builder = builder, - isMinimized = isMinimized, - usesIncreasedHeight = usesIncreasedHeight, - usesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight, + bindParams = bindParams, + entry = entry, + systemUiContext = systemUiContext, + packageContext = packageContext, row = row, notifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider, headsUpStyleProvider = headsUpStyleProvider, @@ -726,7 +717,8 @@ constructor( notification = entry.sbn.notification, messagingStyle = messagingStyle, builder = builder, - systemUiContext = systemUIContext, + systemUiContext = systemUiContext, + redactText = false, ) } else null @@ -736,10 +728,20 @@ constructor( reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE != 0 ) { logger.logAsyncTaskProgress(entry, "inflating public single line view model") - SingleLineViewInflater.inflateRedactedSingleLineViewModel( - systemUIContext, - entry.ranking.isConversation, - ) + if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) { + SingleLineViewInflater.inflateSingleLineViewModel( + notification = entry.sbn.notification, + messagingStyle = messagingStyle, + builder = builder, + systemUiContext = systemUiContext, + redactText = true, + ) + } else { + SingleLineViewInflater.inflateRedactedSingleLineViewModel( + systemUiContext, + entry.ranking.isConversation, + ) + } } else null val headsUpStatusBarModel = @@ -759,16 +761,54 @@ constructor( packageContext = packageContext, remoteViews = remoteViews, contentModel = contentModel, - extractedPromotedNotificationContentModel = promoted, + promotedContent = promotedContent, ) } + private fun createSensitiveContentMessageNotification( + original: Notification, + originalStyle: Notification.Style?, + sysUiContext: Context, + packageContext: Context, + ): Notification.Builder { + val redacted = Notification.Builder(packageContext, original.channelId) + redacted.setContentTitle(original.extras.getCharSequence(Notification.EXTRA_TITLE)) + val redactedMessage = + sysUiContext.getString(R.string.redacted_notification_single_line_text) + + if (originalStyle is MessagingStyle) { + val newStyle = MessagingStyle(originalStyle.user) + newStyle.conversationTitle = originalStyle.conversationTitle + newStyle.isGroupConversation = false + newStyle.conversationType = originalStyle.conversationType + newStyle.shortcutIcon = originalStyle.shortcutIcon + newStyle.setBuilder(redacted) + val latestMessage = MessagingStyle.findLatestIncomingMessage(originalStyle.messages) + if (latestMessage != null) { + val newMessage = + MessagingStyle.Message( + redactedMessage, + latestMessage.timestamp, + latestMessage.senderPerson, + ) + newStyle.addMessage(newMessage) + } + redacted.style = newStyle + } else { + redacted.setContentText(redactedMessage) + } + redacted.setLargeIcon(original.getLargeIcon()) + redacted.setSmallIcon(original.smallIcon) + return redacted + } + private fun createRemoteViews( @InflationFlag reInflateFlags: Int, builder: Notification.Builder, - isMinimized: Boolean, - usesIncreasedHeight: Boolean, - usesIncreasedHeadsUpHeight: Boolean, + bindParams: BindParams, + entry: NotificationEntry, + systemUiContext: Context, + packageContext: Context, row: ExpandableNotificationRow, notifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider, headsUpStyleProvider: HeadsUpStyleProvider, @@ -782,7 +822,11 @@ constructor( entryForLogging, "creating contracted remote view", ) - createContentView(builder, isMinimized, usesIncreasedHeight) + createContentView( + builder, + bindParams.isMinimized, + bindParams.usesIncreasedHeight, + ) } else null val expanded = if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) { @@ -790,7 +834,7 @@ constructor( entryForLogging, "creating expanded remote view", ) - createExpandedView(builder, isMinimized) + createExpandedView(builder, bindParams.isMinimized) } else null val headsUp = if (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0) { @@ -802,13 +846,26 @@ constructor( if (isHeadsUpCompact) { builder.createCompactHeadsUpContentView() } else { - builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight) + builder.createHeadsUpContentView(bindParams.usesIncreasedHeadsUpHeight) } } else null val public = if (reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC != 0) { logger.logAsyncTaskProgress(entryForLogging, "creating public remote view") - builder.makePublicContentView(isMinimized) + if ( + LockscreenOtpRedaction.isEnabled && + bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT + ) { + createSensitiveContentMessageNotification( + entry.sbn.notification, + builder.style, + systemUiContext, + packageContext, + ) + .createContentView(bindParams.usesIncreasedHeight) + } else { + builder.makePublicContentView(bindParams.isMinimized) + } } else null val normalGroupHeader = if ( @@ -1420,8 +1477,7 @@ constructor( entry.setContentModel(result.contentModel) if (PromotedNotificationContentModel.featureFlagEnabled()) { - entry.promotedNotificationContentModel = - result.extractedPromotedNotificationContentModel + entry.promotedNotificationContentModel = result.promotedContent } result.inflatedSmartReplyState?.let { row.privateLayout.setInflatedSmartReplyState(it) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java index 427fb66ca2d0..bc44cb0e1074 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindParams.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE; +import static com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; @@ -31,6 +33,7 @@ public final class RowContentBindParams { private boolean mUseIncreasedHeadsUpHeight; private boolean mViewsNeedReinflation; private @InflationFlag int mContentViews = DEFAULT_INFLATION_FLAGS; + private @RedactionType int mRedactionType = REDACTION_TYPE_NONE; /** * Content views that are out of date and need to be rebound. @@ -58,6 +61,20 @@ public final class RowContentBindParams { } /** + * @return What type of redaction should be used by the public view (if requested) + */ + public @RedactionType int getRedactionType() { + return mRedactionType; + } + + /** + * Set the redaction type, which controls what sort of public view is shown. + */ + public void setRedactionType(@RedactionType int redactionType) { + mRedactionType = redactionType; + } + + /** * Set whether content should use an increased height version of its contracted view. */ public void setUseIncreasedCollapsedHeight(boolean useIncreasedHeight) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java index 89fcda949b5b..53f74161e7fc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java @@ -72,10 +72,8 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> { // Bind/unbind with parameters mBinder.unbindContent(entry, row, contentToUnbind); - BindParams bindParams = new BindParams(); - bindParams.isMinimized = params.useMinimized(); - bindParams.usesIncreasedHeight = params.useIncreasedHeight(); - bindParams.usesIncreasedHeadsUpHeight = params.useIncreasedHeadsUpHeight(); + BindParams bindParams = new BindParams(params.useMinimized(), params.useIncreasedHeight(), + params.useIncreasedHeadsUpHeight(), params.getRedactionType()); boolean forceInflate = params.needsReinflation(); InflationCallback inflationCallback = new InflationCallback() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt index e702f10d7f50..fe2803bfc5d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt @@ -51,6 +51,7 @@ internal object SingleLineViewInflater { * notification, not for legacy messaging notifications * @param builder the recovered Notification Builder * @param systemUiContext the context of Android System UI + * @param redactText indicates if the text needs to be redacted * @return the inflated SingleLineViewModel */ @JvmStatic @@ -59,13 +60,21 @@ internal object SingleLineViewInflater { messagingStyle: MessagingStyle?, builder: Notification.Builder, systemUiContext: Context, + redactText: Boolean, ): SingleLineViewModel { if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) { return SingleLineViewModel(null, null, null) } peopleHelper.init(systemUiContext) var titleText = HybridGroupManager.resolveTitle(notification) - var contentText = HybridGroupManager.resolveText(notification) + var contentText = + if (redactText) { + systemUiContext.getString( + com.android.systemui.res.R.string.redacted_notification_single_line_text + ) + } else { + HybridGroupManager.resolveText(notification) + } if (messagingStyle == null) { return SingleLineViewModel( @@ -81,7 +90,7 @@ internal object SingleLineViewInflater { if (conversationTextData?.conversationTitle?.isNotEmpty() == true) { titleText = conversationTextData.conversationTitle } - if (conversationTextData?.conversationText?.isNotEmpty() == true) { + if (!redactText && conversationTextData?.conversationText?.isNotEmpty() == true) { contentText = conversationTextData.conversationText } 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 7c9d850eaf07..38a70359e816 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 @@ -3729,14 +3729,6 @@ public class NotificationStackScrollLayout // Only when scene container is enabled, mark that we are being dragged so that we start // dispatching the rest of the gesture to scene container. - void startOverscrollAfterExpanding() { - if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return; - getExpandHelper().finishExpanding(); - setIsBeingDragged(true); - } - - // Only when scene container is enabled, mark that we are being dragged so that we start - // dispatching the rest of the gesture to scene container. void startDraggingOnHun() { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return; setIsBeingDragged(true); 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 245b1d29fb79..a33a9ed2df75 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 @@ -2203,11 +2203,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { expandingNotification = mView.isExpandingNotification(); if (mView.getExpandedInThisMotion() && !expandingNotification && wasExpandingBefore && !mView.getDisallowScrollingInThisMotion()) { - // We need to dispatch the overscroll differently when Scene Container is on, - // since NSSL no longer controls its own scroll. + // Finish expansion here, as this gesture will be marked to be sent to + // scene container if (SceneContainerFlag.isEnabled() && !isCancelOrUp) { - mView.startOverscrollAfterExpanding(); - return true; + expandHelper.finishExpanding(); } else { mView.dispatchDownEventToScroller(ev); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt index 42acd7bcdc8a..705845ff984c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt @@ -75,7 +75,7 @@ class SharedNotificationContainer(context: Context, attrs: AttributeSet?) : constraintSet.apply { if (SceneContainerFlag.isEnabled) { when (horizontalPosition) { - is HorizontalPosition.FloatAtEnd -> + is HorizontalPosition.FloatAtStart -> constrainWidth(nsslId, horizontalPosition.width) is HorizontalPosition.MiddleToEdge -> setGuidelinePercent(R.id.nssl_guideline, horizontalPosition.ratio) @@ -83,13 +83,13 @@ class SharedNotificationContainer(context: Context, attrs: AttributeSet?) : } } + connect(nsslId, START, startConstraintId, START, marginStart) if ( !SceneContainerFlag.isEnabled || - horizontalPosition !is HorizontalPosition.FloatAtEnd + horizontalPosition !is HorizontalPosition.FloatAtStart ) { - connect(nsslId, START, startConstraintId, START, marginStart) + connect(nsslId, END, PARENT_ID, END, marginEnd) } - connect(nsslId, END, PARENT_ID, END, marginEnd) connect(nsslId, BOTTOM, PARENT_ID, BOTTOM, marginBottom) connect(nsslId, TOP, PARENT_ID, TOP, marginTop) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index b81c71ebe19b..fc8c70fb8e9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -247,7 +247,7 @@ constructor( Split -> HorizontalPosition.MiddleToEdge(ratio = 0.5f) Dual -> if (isShadeLayoutWide) { - HorizontalPosition.FloatAtEnd( + HorizontalPosition.FloatAtStart( width = getDimensionPixelSize(R.dimen.shade_panel_width) ) } else { @@ -830,10 +830,10 @@ constructor( data class MiddleToEdge(val ratio: Float = 0.5f) : HorizontalPosition /** - * The container has a fixed [width] and is aligned to the end of the screen. In this - * layout, the start edge of the container is floating, i.e. unconstrained. + * The container has a fixed [width] and is aligned to the start of the screen. In this + * layout, the end edge of the container is floating, i.e. unconstrained. */ - data class FloatAtEnd(val width: Int) : HorizontalPosition + data class FloatAtStart(val width: Int) : HorizontalPosition } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt index 86c7c6bd1e86..4751293a16cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt @@ -20,6 +20,7 @@ import android.os.Bundle import android.os.UserHandle import android.view.View import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.animation.TransitionAnimator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -38,7 +39,7 @@ constructor( private val statusBarStateController: SysuiStatusBarStateController, @Main private val mainExecutor: DelayableExecutor, activityStarterInternal: Lazy<ActivityStarterInternalImpl>, - legacyActivityStarter: Lazy<LegacyActivityStarterInternalImpl> + legacyActivityStarter: Lazy<LegacyActivityStarterInternalImpl>, ) : ActivityStarter { private val activityStarterInternal: ActivityStarterInternal = @@ -48,10 +49,23 @@ constructor( legacyActivityStarter.get() } + override fun registerTransition( + cookie: ActivityTransitionAnimator.TransitionCookie, + controllerFactory: ActivityTransitionAnimator.ControllerFactory, + ) { + if (!TransitionAnimator.longLivedReturnAnimationsEnabled()) return + activityStarterInternal.registerTransition(cookie, controllerFactory) + } + + override fun unregisterTransition(cookie: ActivityTransitionAnimator.TransitionCookie) { + if (!TransitionAnimator.longLivedReturnAnimationsEnabled()) return + activityStarterInternal.unregisterTransition(cookie) + } + override fun startPendingIntentDismissingKeyguard(intent: PendingIntent) { activityStarterInternal.startPendingIntentDismissingKeyguard( intent = intent, - dismissShade = true + dismissShade = true, ) } @@ -98,7 +112,7 @@ constructor( intentSentUiThreadCallback: Runnable?, animationController: ActivityTransitionAnimator.Controller?, fillInIntent: Intent?, - extraOptions: Bundle? + extraOptions: Bundle?, ) { activityStarterInternal.startPendingIntentDismissingKeyguard( intent = intent, @@ -115,7 +129,7 @@ constructor( override fun startPendingIntentMaybeDismissingKeyguard( intent: PendingIntent, intentSentUiThreadCallback: Runnable?, - animationController: ActivityTransitionAnimator.Controller? + animationController: ActivityTransitionAnimator.Controller?, ) { activityStarterInternal.startPendingIntentDismissingKeyguard( intent = intent, @@ -245,7 +259,7 @@ constructor( override fun postStartActivityDismissingKeyguard( intent: PendingIntent, - animationController: ActivityTransitionAnimator.Controller? + animationController: ActivityTransitionAnimator.Controller?, ) { postOnUiThread { activityStarterInternal.startPendingIntentDismissingKeyguard( @@ -381,7 +395,7 @@ constructor( postOnUiThread { statusBarStateController.setLeaveOpenOnKeyguardHide(true) activityStarterInternal.executeRunnableDismissingKeyguard( - runnable = { runnable?.let { postOnUiThread(runnable = it) } }, + runnable = { runnable?.let { postOnUiThread(runnable = it) } } ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt index 93ce6e8561ac..5e427fbf1f7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import android.app.PendingIntent +import android.content.ComponentName import android.content.Intent import android.os.Bundle import android.os.UserHandle @@ -27,6 +28,21 @@ import com.android.systemui.plugins.ActivityStarter interface ActivityStarterInternal { /** + * Registers the given [controllerFactory] for launching and closing transitions matching the + * [cookie] and the [ComponentName] that it contains. + */ + fun registerTransition( + cookie: ActivityTransitionAnimator.TransitionCookie, + controllerFactory: ActivityTransitionAnimator.ControllerFactory, + ) + + /** + * Unregisters the [ActivityTransitionAnimator.Controller] previously registered containing the + * given [cookie]. If no such registration exists, this is a no-op. + */ + fun unregisterTransition(cookie: ActivityTransitionAnimator.TransitionCookie) + + /** * Starts a pending intent after dismissing keyguard. * * This can be called in a background thread (to prevent calls in [ActivityIntentHelper] in the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt index f2ef2f0ab48f..33e4fed4073c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt @@ -36,6 +36,7 @@ import com.android.systemui.ActivityIntentHelper import com.android.systemui.Flags import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.animation.DelegateTransitionAnimatorController +import com.android.systemui.animation.TransitionAnimator import com.android.systemui.assist.AssistManager import com.android.systemui.camera.CameraIntents import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor @@ -103,6 +104,44 @@ constructor( private val centralSurfaces: CentralSurfaces? get() = centralSurfacesOptLazy.get().getOrNull() + override fun registerTransition( + cookie: ActivityTransitionAnimator.TransitionCookie, + controllerFactory: ActivityTransitionAnimator.ControllerFactory, + ) { + check(TransitionAnimator.longLivedReturnAnimationsEnabled()) + + val factory = + object : + ActivityTransitionAnimator.ControllerFactory( + controllerFactory.cookie, + controllerFactory.component, + controllerFactory.launchCujType, + controllerFactory.returnCujType, + ) { + override fun createController( + forLaunch: Boolean + ): ActivityTransitionAnimator.Controller { + val baseController = controllerFactory.createController(forLaunch) + val rootView = baseController.transitionContainer.rootView + val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = + statusBarWindowControllerStore.defaultDisplay + .wrapAnimationControllerIfInStatusBar(rootView, baseController) + return if (controllerFromStatusBar.isPresent) { + controllerFromStatusBar.get() + } else { + baseController + } + } + } + + activityTransitionAnimator.register(cookie, factory) + } + + override fun unregisterTransition(cookie: ActivityTransitionAnimator.TransitionCookie) { + check(TransitionAnimator.longLivedReturnAnimationsEnabled()) + activityTransitionAnimator.unregister(cookie) + } + override fun startPendingIntentDismissingKeyguard( intent: PendingIntent, dismissShade: Boolean, @@ -134,7 +173,7 @@ constructor( (skipLockscreenChecks || activityIntentHelper.wouldPendingShowOverLockscreen( intent, - lockScreenUserManager.currentUserId + lockScreenUserManager.currentUserId, )) val animate = @@ -190,7 +229,7 @@ constructor( null, null, null, - options.toBundle() + options.toBundle(), ) } }, @@ -239,7 +278,7 @@ constructor( animationController: ActivityTransitionAnimator.Controller?, customMessage: String?, disallowEnterPictureInPictureWhileLaunching: Boolean, - userHandle: UserHandle? + userHandle: UserHandle?, ) { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return val userHandle: UserHandle = userHandle ?: getActivityUserHandle(intent) @@ -280,7 +319,7 @@ constructor( activityTransitionAnimator.startIntentWithAnimation( animController, animate, - intent.getPackage() + intent.getPackage(), ) { adapter: RemoteAnimationAdapter? -> val options = ActivityOptions(CentralSurfaces.getActivityOptions(displayId, adapter)) @@ -359,7 +398,7 @@ constructor( dismissShade: Boolean, animationController: ActivityTransitionAnimator.Controller?, showOverLockscreenWhenLocked: Boolean, - userHandle: UserHandle? + userHandle: UserHandle?, ) { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return val userHandle = userHandle ?: getActivityUserHandle(intent) @@ -383,7 +422,7 @@ constructor( animationController != null && shouldAnimateLaunch( isActivityIntent = true, - showOverLockscreen = showOverLockscreenWhenLocked + showOverLockscreen = showOverLockscreenWhenLocked, ) var controller: ActivityTransitionAnimator.Controller? = null @@ -413,7 +452,7 @@ constructor( controller, animate, intent.getPackage(), - showOverLockscreenWhenLocked + showOverLockscreenWhenLocked, ) { adapter: RemoteAnimationAdapter? -> TaskStackBuilder.create(context) .addNextIntent(intent) @@ -425,7 +464,7 @@ constructor( action: ActivityStarter.OnDismissAction, cancel: Runnable?, afterKeyguardGone: Boolean, - customMessage: String? + customMessage: String?, ) { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return Log.i(TAG, "Invoking dismissKeyguardThenExecute, afterKeyguardGone: $afterKeyguardGone") @@ -453,7 +492,7 @@ constructor( afterKeyguardGone: Boolean, deferred: Boolean, willAnimateOnKeyguard: Boolean, - customMessage: String? + customMessage: String?, ) { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return val onDismissAction: ActivityStarter.OnDismissAction = @@ -482,12 +521,7 @@ constructor( return willAnimateOnKeyguard } } - dismissKeyguardThenExecute( - onDismissAction, - cancelAction, - afterKeyguardGone, - customMessage, - ) + dismissKeyguardThenExecute(onDismissAction, cancelAction, afterKeyguardGone, customMessage) } override fun shouldAnimateLaunch(isActivityIntent: Boolean): Boolean { @@ -565,7 +599,7 @@ constructor( val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = statusBarWindowControllerStore.defaultDisplay.wrapAnimationControllerIfInStatusBar( rootView, - animationController + animationController, ) if (controllerFromStatusBar.isPresent) { return controllerFromStatusBar.get() @@ -582,7 +616,7 @@ constructor( notifShadeWindowControllerLazy.get(), commandQueue, displayId, - isLaunchForActivity + isLaunchForActivity, ) } } @@ -596,7 +630,7 @@ constructor( */ private fun wrapAnimationControllerForLockscreen( dismissShade: Boolean, - animationController: ActivityTransitionAnimator.Controller? + animationController: ActivityTransitionAnimator.Controller?, ): ActivityTransitionAnimator.Controller? { return animationController?.let { object : DelegateTransitionAnimatorController(it) { @@ -613,7 +647,7 @@ constructor( communalSceneInteractor.snapToScene( newScene = CommunalScenes.Blank, loggingReason = "ActivityStarterInternalImpl", - delayMillis = ActivityTransitionAnimator.TIMINGS.totalDuration + delayMillis = ActivityTransitionAnimator.TIMINGS.totalDuration, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 7bea4800f7fc..6dc25aa5144f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -21,9 +21,10 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; -import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO; -import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; import static androidx.lifecycle.Lifecycle.State.RESUMED; import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; @@ -207,6 +208,7 @@ import com.android.systemui.statusbar.data.repository.StatusBarModeRepositorySto import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -221,7 +223,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.window.StatusBarWindowControllerStore; @@ -2514,12 +2515,15 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { * should update only the status bar components. */ private void setBouncerShowingForStatusBarComponents(boolean bouncerShowing) { - int importance = bouncerShowing - ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS - : IMPORTANT_FOR_ACCESSIBILITY_AUTO; if (!StatusBarConnectedDisplays.isEnabled() && mPhoneStatusBarViewController != null) { + int importance = bouncerShowing + ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + : IMPORTANT_FOR_ACCESSIBILITY_AUTO; mPhoneStatusBarViewController.setImportantForAccessibility(importance); } + int importance = bouncerShowing + ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + : IMPORTANT_FOR_ACCESSIBILITY_NO; mShadeSurface.setImportantForAccessibility(importance); mShadeSurface.setBouncerShowing(bouncerShowing); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 013903a5eb3d..518923eec5ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -33,7 +33,6 @@ import com.android.systemui.log.dagger.KeyguardClockLog; import com.android.systemui.res.R; import com.android.systemui.shade.LargeScreenHeaderHelper; import com.android.systemui.shade.ShadeViewController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView; import javax.inject.Inject; @@ -55,19 +54,6 @@ public class KeyguardClockPositionAlgorithm { private int mKeyguardStatusHeight; /** - * Height of user avatar used by the multi-user switcher. This could either be the - * {@link KeyguardUserSwitcherListView} when it is closed and only the current user's icon is - * visible, or it could be height of the avatar used by the - * {@link com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController}. - */ - private int mUserSwitchHeight; - - /** - * Preferred Y position of user avatar used by the multi-user switcher. - */ - private int mUserSwitchPreferredY; - - /** * Minimum top margin to avoid overlap with status bar or multi-user switcher avatar. */ private int mMinTopMargin; @@ -184,17 +170,13 @@ public class KeyguardClockPositionAlgorithm { * Sets up algorithm values. */ public void setup(int keyguardStatusBarHeaderHeight, float panelExpansion, - int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY, - float dark, float overStretchAmount, boolean bypassEnabled, + int keyguardStatusHeight, float dark, float overStretchAmount, boolean bypassEnabled, int unlockedStackScrollerPadding, float qsExpansion, int cutoutTopInset, boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) { - mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding, - userSwitchHeight); + mMinTopMargin = keyguardStatusBarHeaderHeight + mContainerTopPadding; mPanelExpansion = BouncerPanelExpansionCalculator .getKeyguardClockScaledExpansion(panelExpansion); mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin; - mUserSwitchHeight = userSwitchHeight; - mUserSwitchPreferredY = userSwitchPreferredY; mDarkAmount = dark; mOverStretchAmount = overStretchAmount; mBypassEnabled = bypassEnabled; @@ -210,7 +192,6 @@ public class KeyguardClockPositionAlgorithm { public void run(Result result) { final int y = getClockY(mPanelExpansion, mDarkAmount); result.clockY = y; - result.userSwitchY = getUserSwitcherY(mPanelExpansion); result.clockYFullyDozing = getClockY( 1.0f /* panelExpansion */, 1.0f /* darkAmount */); result.clockAlpha = getClockAlpha(y); @@ -224,7 +205,7 @@ public class KeyguardClockPositionAlgorithm { if (mBypassEnabled) { return mUnlockedStackScrollerPadding; } else if (mIsSplitShade) { - return getClockY(1.0f, mDarkAmount) + mUserSwitchHeight; + return getClockY(1.0f, mDarkAmount); } else { return getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight; } @@ -236,7 +217,7 @@ public class KeyguardClockPositionAlgorithm { } else if (mIsSplitShade) { // mCurrentBurnInOffsetY is subtracted to make notifications not follow clock adjustment // for burn-in. It can make pulsing notification go too high and it will get clipped - return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight + return clockYPosition - mSplitShadeTopNotificationsMargin - (int) mCurrentBurnInOffsetY; } else { return clockYPosition + mKeyguardStatusHeight; @@ -251,7 +232,7 @@ public class KeyguardClockPositionAlgorithm { if (mBypassEnabled) { return mUnlockedStackScrollerPadding - nsslTop; } else if (mIsSplitShade) { - return mSplitShadeTargetTopMargin + mUserSwitchHeight - nsslTop; + return mSplitShadeTargetTopMargin - nsslTop; } else { // Non-bypass portrait shade already uses values from nsslTop // so we don't need to subtract it here. @@ -339,17 +320,6 @@ public class KeyguardClockPositionAlgorithm { return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount); } - private int getUserSwitcherY(float panelExpansion) { - float userSwitchYRegular = mUserSwitchPreferredY; - float userSwitchYBouncer = -mKeyguardStatusHeight - mUserSwitchHeight; - - // Move user-switch up while collapsing the shade - float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion); - float userSwitchY = MathUtils.lerp(userSwitchYBouncer, userSwitchYRegular, shadeExpansion); - - return (int) (userSwitchY + mOverStretchAmount); - } - /** * We might want to fade out the clock when the user is swiping up. * One exception is when the bouncer will become visible, in this cause the clock @@ -391,11 +361,6 @@ public class KeyguardClockPositionAlgorithm { public int clockY; /** - * The y translation of the multi-user switch. - */ - public int userSwitchY; - - /** * The y translation of the clock when we're fully dozing. */ public int clockYFullyDozing; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt index d7cc65d22663..d7a29c36f2ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt @@ -36,6 +36,7 @@ import com.android.systemui.ActivityIntentHelper import com.android.systemui.Flags.mediaLockscreenLaunchAnimation import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.animation.DelegateTransitionAnimatorController +import com.android.systemui.animation.TransitionAnimator import com.android.systemui.assist.AssistManager import com.android.systemui.camera.CameraIntents import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor @@ -98,6 +99,44 @@ constructor( private val centralSurfaces: CentralSurfaces? get() = centralSurfacesOptLazy.get().getOrNull() + override fun registerTransition( + cookie: ActivityTransitionAnimator.TransitionCookie, + controllerFactory: ActivityTransitionAnimator.ControllerFactory, + ) { + check(TransitionAnimator.longLivedReturnAnimationsEnabled()) + + val factory = + object : + ActivityTransitionAnimator.ControllerFactory( + controllerFactory.cookie, + controllerFactory.component, + controllerFactory.launchCujType, + controllerFactory.returnCujType, + ) { + override fun createController( + forLaunch: Boolean + ): ActivityTransitionAnimator.Controller { + val baseController = controllerFactory.createController(forLaunch) + val rootView = baseController.transitionContainer.rootView + val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = + statusBarWindowControllerStore.defaultDisplay + .wrapAnimationControllerIfInStatusBar(rootView, baseController) + return if (controllerFromStatusBar.isPresent) { + controllerFromStatusBar.get() + } else { + baseController + } + } + } + + activityTransitionAnimator.register(cookie, factory) + } + + override fun unregisterTransition(cookie: ActivityTransitionAnimator.TransitionCookie) { + check(TransitionAnimator.longLivedReturnAnimationsEnabled()) + activityTransitionAnimator.unregister(cookie) + } + override fun startActivityDismissingKeyguard( intent: Intent, dismissShade: Boolean, @@ -116,7 +155,7 @@ constructor( val willLaunchResolverActivity: Boolean = activityIntentHelper.wouldLaunchResolverActivity( intent, - lockScreenUserManager.currentUserId + lockScreenUserManager.currentUserId, ) val animate = @@ -147,7 +186,7 @@ constructor( activityTransitionAnimator.startIntentWithAnimation( animController, animate, - intent.getPackage() + intent.getPackage(), ) { adapter: RemoteAnimationAdapter? -> val options = ActivityOptions(CentralSurfaces.getActivityOptions(displayId, adapter)) @@ -259,7 +298,7 @@ constructor( (skipLockscreenChecks || activityIntentHelper.wouldPendingShowOverLockscreen( intent, - lockScreenUserManager.currentUserId + lockScreenUserManager.currentUserId, )) val animate = @@ -317,7 +356,7 @@ constructor( null, null, null, - options.toBundle() + options.toBundle(), ) } }, @@ -409,7 +448,7 @@ constructor( controller, animate, intent.getPackage(), - showOverLockscreenWhenLocked + showOverLockscreenWhenLocked, ) { adapter: RemoteAnimationAdapter? -> TaskStackBuilder.create(context) .addNextIntent(intent) @@ -495,12 +534,7 @@ constructor( return willAnimateOnKeyguard } } - dismissKeyguardThenExecute( - onDismissAction, - cancelAction, - afterKeyguardGone, - customMessage, - ) + dismissKeyguardThenExecute(onDismissAction, cancelAction, afterKeyguardGone, customMessage) } /** @@ -528,7 +562,7 @@ constructor( val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = statusBarWindowControllerStore.defaultDisplay.wrapAnimationControllerIfInStatusBar( rootView, - animationController + animationController, ) if (controllerFromStatusBar.isPresent) { return controllerFromStatusBar.get() @@ -545,7 +579,7 @@ constructor( notifShadeWindowControllerLazy.get(), commandQueue, displayId, - isLaunchForActivity + isLaunchForActivity, ) } } @@ -559,7 +593,7 @@ constructor( */ private fun wrapAnimationControllerForLockscreen( dismissShade: Boolean, - animationController: ActivityTransitionAnimator.Controller? + animationController: ActivityTransitionAnimator.Controller?, ): ActivityTransitionAnimator.Controller? { return animationController?.let { object : DelegateTransitionAnimatorController(it) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index bd1360f6e939..3749b96199f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -1178,7 +1178,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void startPreHideAnimation(Runnable finishRunnable) { if (primaryBouncerIsShowing()) { mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable); - mShadeLockscreenInteractor.startBouncerPreHideAnimation(); // We update the state (which will show the keyguard) only if an animation will run on // the keyguard. If there is no animation, we wait before updating the state so that we diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 0fac6448909c..4d1d64ea24c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -251,11 +251,11 @@ class StatusBarNotificationPresenter implements NotificationPresenter, CommandQu mPowerInteractor.wakeUpIfDozing("NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE); if (nowExpanded) { if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { - mShadeTransitionController.goToLockedShade(clickedEntry.getRow()); - } else if (clickedEntry.isSensitive().getValue() - && isInLockedDownShade()) { + mShadeTransitionController.goToLockedShade( + clickedEntry.getRow(), /* needsQSAnimation = */ true); + } else if (clickedEntry.isSensitive().getValue() && isInLockedDownShade()) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); - // launch the bouncer + // launch the bouncer if the device is locked mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */ , null /* cancelRunnable */, false /* afterKeyguardGone */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt index bfdc8bd5e4c8..96666d83b39b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt @@ -32,6 +32,8 @@ import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneMod import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistryImpl import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable +import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepositoryImpl import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor @@ -48,6 +50,8 @@ import com.android.systemui.statusbar.pipeline.satellite.data.RealDeviceBasedSat import com.android.systemui.statusbar.pipeline.satellite.data.prod.DeviceBasedSatelliteRepositoryImpl import com.android.systemui.statusbar.pipeline.satellite.ui.viewmodel.DeviceBasedSatelliteViewModel import com.android.systemui.statusbar.pipeline.satellite.ui.viewmodel.DeviceBasedSatelliteViewModelImpl +import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants +import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstantsImpl import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder @@ -106,6 +110,9 @@ abstract class StatusBarPipelineModule { impl: DeviceBasedSatelliteViewModelImpl ): DeviceBasedSatelliteViewModel + @Binds + abstract fun connectivityConstants(impl: ConnectivityConstantsImpl): ConnectivityConstants + @Binds abstract fun wifiRepository(impl: WifiRepositorySwitcher): WifiRepository @Binds abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor @@ -120,6 +127,9 @@ abstract class StatusBarPipelineModule { @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy @Binds + abstract fun carrierConfigRepository(impl: CarrierConfigRepositoryImpl): CarrierConfigRepository + + @Binds abstract fun subscriptionManagerProxy( impl: SubscriptionManagerProxyImpl ): SubscriptionManagerProxy diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt index 0871c8637652..5f33a754a47e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt @@ -48,11 +48,7 @@ import kotlinx.coroutines.flow.asStateFlow * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly * updated when a new carrier config comes down */ -class SystemUiCarrierConfig -internal constructor( - val subId: Int, - defaultConfig: PersistableBundle, -) { +class SystemUiCarrierConfig constructor(val subId: Int, defaultConfig: PersistableBundle) { @VisibleForTesting var isUsingDefault = true private set @@ -67,17 +63,11 @@ internal constructor( /** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */ val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config - private val showNetworkSlice = - BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig) + private val showNetworkSlice = BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig) /** Flow tracking the [KEY_SHOW_5G_SLICE_ICON_BOOL] config */ val allowNetworkSliceIndicator: StateFlow<Boolean> = showNetworkSlice.config - private val trackedConfigs = - listOf( - inflateSignalStrength, - showOperatorName, - showNetworkSlice, - ) + private val trackedConfigs = listOf(inflateSignalStrength, showOperatorName, showNetworkSlice) /** Ingest a new carrier config, and switch all of the tracked keys over to the new values */ fun processNewCarrierConfig(config: PersistableBundle) { @@ -98,10 +88,7 @@ internal constructor( } /** Extracts [key] from the carrier config, and stores it in a flow */ -private class BooleanCarrierConfig( - val key: String, - defaultConfig: PersistableBundle, -) { +private class BooleanCarrierConfig(val key: String, defaultConfig: PersistableBundle) { private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key)) val config = _configValue.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt index 016ba5fddcbd..30c529a9034a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt @@ -16,31 +16,8 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository -import android.content.IntentFilter -import android.os.PersistableBundle import android.telephony.CarrierConfigManager -import android.telephony.SubscriptionManager -import android.util.SparseArray -import androidx.annotation.VisibleForTesting -import androidx.core.util.getOrElse -import androidx.core.util.isEmpty -import androidx.core.util.keyIterator -import com.android.systemui.Dumpable -import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dump.DumpManager -import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig -import java.io.PrintWriter -import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.shareIn /** * Meant to be the source of truth regarding CarrierConfigs. These are configuration objects defined @@ -50,87 +27,13 @@ import kotlinx.coroutines.flow.shareIn * * See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked */ -@SysUISingleton -class CarrierConfigRepository -@Inject -constructor( - broadcastDispatcher: BroadcastDispatcher, - private val carrierConfigManager: CarrierConfigManager?, - dumpManager: DumpManager, - logger: MobileInputLogger, - @Application scope: CoroutineScope, -) : Dumpable { - private var isListening = false - private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() } - // Used for logging the default config in the dumpsys - private val defaultConfigForLogs: SystemUiCarrierConfig by lazy { - SystemUiCarrierConfig(-1, defaultConfig) - } - - private val configs = SparseArray<SystemUiCarrierConfig>() - - init { - dumpManager.registerNormalDumpable(this) - } - - @VisibleForTesting - val carrierConfigStream: SharedFlow<Pair<Int, PersistableBundle>> = - broadcastDispatcher - .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - intent, - _ -> - intent.getIntExtra( - CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID - ) - } - .onEach { logger.logCarrierConfigChanged(it) } - .filter { SubscriptionManager.isValidSubscriptionId(it) } - .mapNotNull { subId -> - val config = carrierConfigManager?.getConfigForSubId(subId) - config?.let { subId to it } - } - .shareIn(scope, SharingStarted.WhileSubscribed()) - +interface CarrierConfigRepository { /** * Start this repository observing broadcasts for **all** carrier configuration updates. Must be * called in order to keep SystemUI in sync with [CarrierConfigManager]. */ - suspend fun startObservingCarrierConfigUpdates() { - isListening = true - carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) } - } - - /** Update or create the [SystemUiCarrierConfig] for subId with the override */ - private fun updateCarrierConfig(subId: Int, config: PersistableBundle) { - val configToUpdate = getOrCreateConfigForSubId(subId) - configToUpdate.processNewCarrierConfig(config) - } + suspend fun startObservingCarrierConfigUpdates() /** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */ - fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig { - return configs.getOrElse(subId) { - val config = SystemUiCarrierConfig(subId, defaultConfig) - val carrierConfig = carrierConfigManager?.getConfigForSubId(subId) - if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig) - configs.put(subId, config) - config - } - } - - override fun dump(pw: PrintWriter, args: Array<out String>) { - pw.println("isListening: $isListening") - if (configs.isEmpty()) { - pw.println("no carrier configs loaded") - } else { - pw.println("Carrier configs by subId") - configs.keyIterator().forEach { - pw.println(" subId=$it") - pw.println(" config=${configs.get(it).toStringConsideringDefaults()}") - } - // Finally, print the default config - pw.println("Default config:") - pw.println(" $defaultConfigForLogs") - } - } + fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt new file mode 100644 index 000000000000..7ed6b05a4320 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.data.repository + +import android.content.IntentFilter +import android.os.PersistableBundle +import android.telephony.CarrierConfigManager +import android.telephony.SubscriptionManager +import android.util.SparseArray +import androidx.annotation.VisibleForTesting +import androidx.core.util.getOrElse +import androidx.core.util.isEmpty +import androidx.core.util.keyIterator +import com.android.systemui.Dumpable +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig +import java.io.PrintWriter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach + +@SysUISingleton +class CarrierConfigRepositoryImpl +@Inject +constructor( + broadcastDispatcher: BroadcastDispatcher, + private val carrierConfigManager: CarrierConfigManager?, + dumpManager: DumpManager, + logger: MobileInputLogger, + @Application scope: CoroutineScope, +) : CarrierConfigRepository, Dumpable { + private var isListening = false + private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() } + // Used for logging the default config in the dumpsys + private val defaultConfigForLogs: SystemUiCarrierConfig by lazy { + SystemUiCarrierConfig(-1, defaultConfig) + } + + private val configs = SparseArray<SystemUiCarrierConfig>() + + init { + dumpManager.registerNormalDumpable(this) + } + + @VisibleForTesting + val carrierConfigStream: Flow<Pair<Int, PersistableBundle>> = + broadcastDispatcher + .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { + intent, + _ -> + intent.getIntExtra( + CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + ) + } + .onEach { logger.logCarrierConfigChanged(it) } + .filter { SubscriptionManager.isValidSubscriptionId(it) } + .mapNotNull { subId -> + val config = carrierConfigManager?.getConfigForSubId(subId) + config?.let { subId to it } + } + + override suspend fun startObservingCarrierConfigUpdates() { + isListening = true + carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) } + } + + /** Update or create the [SystemUiCarrierConfig] for subId with the override */ + private fun updateCarrierConfig(subId: Int, config: PersistableBundle) { + val configToUpdate = getOrCreateConfigForSubId(subId) + configToUpdate.processNewCarrierConfig(config) + } + + override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig { + return configs.getOrElse(subId) { + val config = SystemUiCarrierConfig(subId, defaultConfig) + val carrierConfig = carrierConfigManager?.getConfigForSubId(subId) + if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig) + configs.put(subId, config) + config + } + } + + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("isListening: $isListening") + if (configs.isEmpty()) { + pw.println("no carrier configs loaded") + } else { + pw.println("Carrier configs by subId") + configs.keyIterator().forEach { + pw.println(" subId=$it") + pw.println(" config=${configs.get(it).toStringConsideringDefaults()}") + } + // Finally, print the default config + pw.println("Default config:") + pw.println(" $defaultConfigForLogs") + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractor.kt new file mode 100644 index 000000000000..8b7f34579b04 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractor.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig +import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +/** Business logic for [CarrierConfigRepository] */ +@SysUISingleton +class CarrierConfigInteractor +@Inject +constructor( + repo: CarrierConfigRepository, + iconsInteractor: MobileIconsInteractor, + @Application scope: CoroutineScope, +) { + val defaultDataSubscriptionCarrierConfig: StateFlow<SystemUiCarrierConfig?> = + iconsInteractor.defaultDataSubId + .map { repo.getOrCreateConfigForSubId(it) } + .stateIn(scope, SharingStarted.WhileSubscribed(), null) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index 28fff4e68935..0b3c491e56fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -71,6 +71,9 @@ interface MobileIconsInteractor { /** List of subscriptions, potentially filtered for CBRS */ val filteredSubscriptions: Flow<List<SubscriptionModel>> + /** Subscription ID of the current default data subscription */ + val defaultDataSubId: Flow<Int> + /** * The current list of [MobileIconInteractor]s associated with the current list of * [filteredSubscriptions] @@ -82,7 +85,7 @@ interface MobileIconsInteractor { /** * Flow providing a reference to the Interactor for the active data subId. This represents the - * [MobileConnectionInteractor] responsible for the active data connection, if any. + * [MobileIconInteractor] responsible for the active data connection, if any. */ val activeDataIconInteractor: StateFlow<MobileIconInteractor?> @@ -280,6 +283,8 @@ constructor( } } + override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId + override val icons = filteredSubscriptions .mapLatest { subs -> @@ -321,7 +326,7 @@ constructor( mobileConnectionsRepo.defaultMobileIconMapping.stateIn( scope, SharingStarted.WhileSubscribed(), - initialValue = mapOf() + initialValue = mapOf(), ) override val alwaysShowDataRatIcon: StateFlow<Boolean> = @@ -350,7 +355,7 @@ constructor( mobileConnectionsRepo.defaultMobileIconGroup.stateIn( scope, SharingStarted.WhileSubscribed(), - initialValue = TelephonyIcons.G + initialValue = TelephonyIcons.G, ) /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt index 9ea167f4815c..09314efdedc0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt @@ -19,9 +19,9 @@ package com.android.systemui.statusbar.pipeline.shared import android.content.Context import android.telephony.TelephonyManager import com.android.systemui.Dumpable -import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager +import com.android.systemui.res.R import java.io.PrintWriter import javax.inject.Inject @@ -30,23 +30,26 @@ import javax.inject.Inject * * Stored in a class for logging purposes. */ +interface ConnectivityConstants { + /** True if this device has the capability for data connections and false otherwise. */ + val hasDataCapabilities: Boolean + + /** True if we should show the activityIn/activityOut icons and false otherwise */ + val shouldShowActivityConfig: Boolean +} + @SysUISingleton -class ConnectivityConstants +class ConnectivityConstantsImpl @Inject -constructor( - context: Context, - dumpManager: DumpManager, - telephonyManager: TelephonyManager, -) : Dumpable { +constructor(context: Context, dumpManager: DumpManager, telephonyManager: TelephonyManager) : + ConnectivityConstants, Dumpable { init { dumpManager.registerNormalDumpable("ConnectivityConstants", this) } - /** True if this device has the capability for data connections and false otherwise. */ - val hasDataCapabilities = telephonyManager.isDataCapable + override val hasDataCapabilities = telephonyManager.isDataCapable - /** True if we should show the activityIn/activityOut icons and false otherwise */ - val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity) + override val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity) override fun dump(pw: PrintWriter, args: Array<out String>) { pw.apply { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractor.kt new file mode 100644 index 000000000000..becf6e57de41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractor.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.domain.interactor + +import android.content.res.Resources +import android.provider.Settings +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.res.R +import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** A place to define the blocklist/allowlist for home status bar icons */ +@SysUISingleton +class HomeStatusBarIconBlockListInteractor +@Inject +constructor(@Main res: Resources, secureSettingsRepository: SecureSettingsRepository) { + private val defaultBlockedIcons = + res.getStringArray(R.array.config_collapsed_statusbar_icon_blocklist) + + private val vibrateIconSlot = res.getString(com.android.internal.R.string.status_bar_volume) + + /** Tracks the user setting [Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON] */ + private val shouldShowVibrateIcon: Flow<Boolean> = + secureSettingsRepository.boolSetting(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, false) + + val iconBlockList: Flow<List<String>> = + shouldShowVibrateIcon.map { + val defaultSet = defaultBlockedIcons.toMutableSet() + // It's possible that the vibrate icon was in the default blocklist, so we manually + // merge the setting and list + if (it) { + defaultSet.remove(vibrateIconSlot) + } else { + defaultSet.add(vibrateIconSlot) + } + + defaultSet.toList() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractor.kt index a0cb8298bdb2..b94ef03abdde 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractor.kt @@ -18,19 +18,30 @@ package com.android.systemui.statusbar.pipeline.shared.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor +import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.CarrierConfigInteractor import com.android.systemui.statusbar.pipeline.shared.domain.model.StatusBarDisableFlagsVisibilityModel import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map /** * Interactor for the home screen status bar (aka * [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment]). */ +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton -class CollapsedStatusBarInteractor +class HomeStatusBarInteractor @Inject -constructor(disableFlagsInteractor: DisableFlagsInteractor) { +constructor( + airplaneModeInteractor: AirplaneModeInteractor, + carrierConfigInteractor: CarrierConfigInteractor, + disableFlagsInteractor: DisableFlagsInteractor, +) { /** * The visibilities of various status bar child views, based only on the information we received * from disable flags. @@ -44,4 +55,21 @@ constructor(disableFlagsInteractor: DisableFlagsInteractor) { animate = it.animate, ) } + + private val defaultDataSubConfigShowOperatorView = + carrierConfigInteractor.defaultDataSubscriptionCarrierConfig.flatMapLatest { + it?.showOperatorNameInStatusBar ?: flowOf(false) + } + + /** + * True if the carrier config for the default data subscription has + * [SystemUiCarrierConfig.showOperatorNameInStatusBar] set and the device is not in airplane + * mode + */ + val shouldShowOperatorName: Flow<Boolean> = + combine(defaultDataSubConfigShowOperatorView, airplaneModeInteractor.isAirplaneMode) { + showOperatorName, + isAirplaneMode -> + showOperatorName && !isAirplaneMode + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarIconBlockListBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarIconBlockListBinder.kt new file mode 100644 index 000000000000..e247f0d14db1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarIconBlockListBinder.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.ui.binder + +import android.view.View +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.phone.ui.IconManager +import kotlinx.coroutines.flow.Flow + +object HomeStatusBarIconBlockListBinder { + fun bind(view: View, iconManager: IconManager, iconList: Flow<List<String>>) { + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + iconList.collect { newBlockList -> iconManager.setBlockList(newBlockList) } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt index d9b2bd1d66c9..7e06c35315f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.shared.ui.binder import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.view.View +import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -204,6 +205,18 @@ constructor( } if (StatusBarRootModernization.isEnabled) { + val operatorNameView = view.requireViewById<View>(R.id.operator_name_frame) + StatusBarOperatorNameViewBinder.bind( + operatorNameView, + viewModel.operatorNameViewModel, + viewModel::areaTint, + ) + launch { + viewModel.shouldShowOperatorNameView.collect { + operatorNameView.isVisible = it + } + } + val clockView = view.requireViewById<View>(R.id.clock) launch { viewModel.isClockVisible.collect { clockView.adjustVisibility(it) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/StatusBarOperatorNameViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/StatusBarOperatorNameViewBinder.kt new file mode 100644 index 000000000000..b7744d34560d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/StatusBarOperatorNameViewBinder.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.ui.binder + +import android.view.View +import android.widget.TextView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R +import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.StatusBarOperatorNameViewModel +import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.StatusBarTintColor +import com.android.systemui.util.view.viewBoundsOnScreen +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch + +object StatusBarOperatorNameViewBinder { + fun bind( + operatorFrameView: View, + viewModel: StatusBarOperatorNameViewModel, + areaTint: (Int) -> Flow<StatusBarTintColor>, + ) { + operatorFrameView.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + val displayId = operatorFrameView.display.displayId + + val operatorNameText = + operatorFrameView.requireViewById<TextView>(R.id.operator_name) + launch { viewModel.operatorName.collect { operatorNameText.text = it } } + + launch { + val tint = areaTint(displayId) + tint.collect { statusBarTintColors -> + operatorNameText.setTextColor( + statusBarTintColors.tint(operatorNameText.viewBoundsOnScreen()) + ) + } + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt index 5614d82c2e4d..ebf439161a9d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt @@ -44,6 +44,7 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.statusbar.phone.ui.DarkIconManager import com.android.systemui.statusbar.phone.ui.StatusBarIconController +import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarIconBlockListBinder import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel @@ -150,6 +151,11 @@ fun StatusBarRoot( darkIconDispatcher, ) iconController.addIconGroup(darkIconManager) + HomeStatusBarIconBlockListBinder.bind( + statusIconContainer, + darkIconManager, + statusBarViewModel.iconBlockList, + ) if (!StatusBarChipsModernization.isEnabled) { ongoingCallController.setChipView( 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 6e9e1ec7253c..7f9a80b2e62f 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 @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel +import android.annotation.ColorInt +import android.graphics.Rect import android.view.View import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -27,6 +29,7 @@ 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.TransitionState +import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -43,8 +46,10 @@ import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotif import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor +import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor -import com.android.systemui.statusbar.pipeline.shared.domain.interactor.CollapsedStatusBarInteractor +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarIconBlockListInteractor +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarInteractor import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel.VisibilityModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -52,6 +57,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter @@ -90,6 +96,9 @@ interface HomeStatusBarViewModel { */ val ongoingActivityChips: StateFlow<MultipleOngoingActivityChipsModel> + /** View model for the carrier name that may show in the status bar based on carrier config */ + val operatorNameViewModel: StatusBarOperatorNameViewModel + /** * True if the current scene can show the home status bar (aka this status bar), and false if * the current scene should never show the home status bar. @@ -99,6 +108,8 @@ interface HomeStatusBarViewModel { */ val isHomeStatusBarAllowedByScene: StateFlow<Boolean> + /** True if the operator name view is not hidden due to HUN or other visibility state */ + val shouldShowOperatorNameView: Flow<Boolean> val isClockVisible: Flow<VisibilityModel> val isNotificationIconContainerVisible: Flow<VisibilityModel> /** @@ -108,6 +119,9 @@ interface HomeStatusBarViewModel { */ val systemInfoCombinedVis: StateFlow<SystemInfoCombinedVisibilityModel> + /** Which icons to block from the home status bar */ + val iconBlockList: Flow<List<String>> + /** * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where * status bar and navigation icons dim. In this mode, a notification dot appears where the @@ -119,6 +133,12 @@ interface HomeStatusBarViewModel { */ fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> + /** + * Given a displayId, returns a flow of [StatusBarTintColor], a functional interface that will + * allow a view to calculate its correct tint depending on location + */ + fun areaTint(displayId: Int): Flow<StatusBarTintColor> + /** Models the current visibility for a specific child view of status bar. */ data class VisibilityModel( @View.Visibility val visibility: Int, @@ -137,12 +157,15 @@ interface HomeStatusBarViewModel { class HomeStatusBarViewModelImpl @Inject constructor( - collapsedStatusBarInteractor: CollapsedStatusBarInteractor, + homeStatusBarInteractor: HomeStatusBarInteractor, + homeStatusBarIconBlockListInteractor: HomeStatusBarIconBlockListInteractor, private val lightsOutInteractor: LightsOutInteractor, private val notificationsInteractor: ActiveNotificationsInteractor, + private val darkIconInteractor: DarkIconInteractor, headsUpNotificationInteractor: HeadsUpNotificationInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, keyguardInteractor: KeyguardInteractor, + override val operatorNameViewModel: StatusBarOperatorNameViewModel, sceneInteractor: SceneInteractor, sceneContainerOcclusionInteractor: SceneContainerOcclusionInteractor, shadeInteractor: ShadeInteractor, @@ -192,6 +215,21 @@ constructor( .distinctUntilChanged() } + override fun areaTint(displayId: Int): Flow<StatusBarTintColor> = + darkIconInteractor + .darkState(displayId) + .map { (areas: Collection<Rect>, tint: Int) -> + StatusBarTintColor { viewBounds: Rect -> + if (DarkIconDispatcher.isInAreas(areas, viewBounds)) { + tint + } else { + DarkIconDispatcher.DEFAULT_ICON_TINT + } + } + } + .conflate() + .distinctUntilChanged() + /** * True if the current SysUI state can show the home status bar (aka this status bar), and false * if we shouldn't be showing any part of the home status bar. @@ -233,11 +271,25 @@ constructor( primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Shown } } + override val shouldShowOperatorNameView: Flow<Boolean> = + combine( + shouldHomeStatusBarBeVisible, + headsUpNotificationInteractor.statusBarHeadsUpState, + homeStatusBarInteractor.visibilityViaDisableFlags, + homeStatusBarInteractor.shouldShowOperatorName, + ) { shouldStatusBarBeVisible, headsUpState, visibilityViaDisableFlags, shouldShowOperator -> + val hideForHeadsUp = headsUpState == PinnedStatus.PinnedBySystem + shouldStatusBarBeVisible && + !hideForHeadsUp && + visibilityViaDisableFlags.isSystemInfoAllowed && + shouldShowOperator + } + override val isClockVisible: Flow<VisibilityModel> = combine( shouldHomeStatusBarBeVisible, headsUpNotificationInteractor.statusBarHeadsUpState, - collapsedStatusBarInteractor.visibilityViaDisableFlags, + homeStatusBarInteractor.visibilityViaDisableFlags, ) { shouldStatusBarBeVisible, headsUpState, visibilityViaDisableFlags -> val hideClockForHeadsUp = headsUpState == PinnedStatus.PinnedBySystem val showClock = @@ -252,7 +304,7 @@ constructor( combine( shouldHomeStatusBarBeVisible, isAnyChipVisible, - collapsedStatusBarInteractor.visibilityViaDisableFlags, + homeStatusBarInteractor.visibilityViaDisableFlags, ) { shouldStatusBarBeVisible, anyChipVisible, visibilityViaDisableFlags -> val showNotificationIconContainer = if (anyChipVisible) { @@ -268,10 +320,9 @@ constructor( } private val isSystemInfoVisible = - combine( - shouldHomeStatusBarBeVisible, - collapsedStatusBarInteractor.visibilityViaDisableFlags, - ) { shouldStatusBarBeVisible, visibilityViaDisableFlags -> + combine(shouldHomeStatusBarBeVisible, homeStatusBarInteractor.visibilityViaDisableFlags) { + shouldStatusBarBeVisible, + visibilityViaDisableFlags -> val showSystemInfo = shouldStatusBarBeVisible && visibilityViaDisableFlags.isSystemInfoAllowed VisibilityModel(showSystemInfo.toVisibleOrGone(), visibilityViaDisableFlags.animate) @@ -293,6 +344,9 @@ constructor( ), ) + override val iconBlockList: Flow<List<String>> = + homeStatusBarIconBlockListInteractor.iconBlockList + @View.Visibility private fun Boolean.toVisibleOrGone(): Int { return if (this) View.VISIBLE else View.GONE @@ -302,3 +356,8 @@ constructor( @View.Visibility private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE } + +/** Lookup the color for a given view in the status bar */ +fun interface StatusBarTintColor { + @ColorInt fun tint(viewBounds: Rect): Int +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt new file mode 100644 index 000000000000..7ae74c3bfb65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModel.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest + +/** + * View model for the operator name (aka carrier name) of the carrier for the default data + * subscription. + */ +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton +class StatusBarOperatorNameViewModel +@Inject +constructor(mobileIconsInteractor: MobileIconsInteractor) { + val operatorName: Flow<String?> = + mobileIconsInteractor.defaultDataSubId.flatMapLatest { + mobileIconsInteractor.getMobileConnectionInteractorForSubId(it).carrierName + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index 78954dea27ba..8b60ee56d5f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -192,7 +192,7 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> mUiEventLogger.log( LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP); - mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground.getContext(), + mUserSwitchDialogController.showDialog( Expandable.fromView(mUserAvatarViewWithBackground)); }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java deleted file mode 100644 index 3eeb59de5911..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import android.content.Context; -import android.graphics.Color; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import androidx.core.graphics.ColorUtils; - -import com.android.app.animation.Interpolators; -import com.android.keyguard.KeyguardConstants; -import com.android.systemui.qs.tiles.UserDetailItemView; -import com.android.systemui.res.R; - -/** - * Displays a user on the keyguard user switcher. - */ -public class KeyguardUserDetailItemView extends UserDetailItemView { - - private static final String TAG = "KeyguardUserDetailItemView"; - private static final boolean DEBUG = KeyguardConstants.DEBUG; - - private static final int ANIMATION_DURATION_FADE_NAME = 240; - - private float mDarkAmount; - private int mTextColor; - - public KeyguardUserDetailItemView(Context context) { - this(context, null); - } - - public KeyguardUserDetailItemView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public KeyguardUserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public KeyguardUserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - protected int getFontSizeDimen() { - return R.dimen.kg_user_switcher_text_size; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mTextColor = mName.getCurrentTextColor(); - updateDark(); - } - - /** - * Update visibility of this view. - * - * @param showItem If true, this item is visible on the screen to the user. Generally this - * means that the item would be clickable. If false, item visibility will be - * set to GONE and hidden entirely. - * @param showTextName Whether or not the name should be shown next to the icon. If false, - * only the icon is shown. - * @param animate Whether the transition should be animated. Note, this only applies to - * animating the text name. The item itself will not animate (i.e. fade in/out). - * Instead, we delegate that to the parent view. - */ - void updateVisibilities(boolean showItem, boolean showTextName, boolean animate) { - if (DEBUG) { - Log.d(TAG, String.format("updateVisibilities itemIsShown=%b nameIsShown=%b animate=%b", - showItem, showTextName, animate)); - } - - getBackground().setAlpha((showItem && showTextName) ? 255 : 0); - - if (showItem) { - if (showTextName) { - mName.setVisibility(View.VISIBLE); - if (animate) { - mName.setAlpha(0f); - mName.animate() - .alpha(1f) - .setDuration(ANIMATION_DURATION_FADE_NAME) - .setInterpolator(Interpolators.ALPHA_IN); - } else { - mName.setAlpha(1f); - } - } else { - if (animate) { - mName.setVisibility(View.VISIBLE); - mName.setAlpha(1f); - mName.animate() - .alpha(0f) - .setDuration(ANIMATION_DURATION_FADE_NAME) - .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction(() -> { - mName.setVisibility(View.GONE); - mName.setAlpha(1f); - }); - } else { - mName.setVisibility(View.GONE); - mName.setAlpha(1f); - } - } - setVisibility(View.VISIBLE); - setAlpha(1f); - } else { - // If item isn't shown, don't animate. The parent class will animate the view instead - setVisibility(View.GONE); - setAlpha(1f); - mName.setVisibility(showTextName ? View.VISIBLE : View.GONE); - mName.setAlpha(1f); - } - } - - /** - * Set the amount (ratio) that the device has transitioned to doze. - * - * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. - */ - public void setDarkAmount(float darkAmount) { - if (mDarkAmount == darkAmount) { - return; - } - mDarkAmount = darkAmount; - updateDark(); - } - - private void updateDark() { - final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount); - mName.setTextColor(blendedTextColor); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java deleted file mode 100644 index 770f441799b9..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.database.DataSetObserver; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.os.UserHandle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.android.app.animation.Interpolators; -import com.android.keyguard.KeyguardConstants; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.keyguard.KeyguardVisibilityHelper; -import com.android.keyguard.dagger.KeyguardUserSwitcherScope; -import com.android.settingslib.drawable.CircleFramedDrawable; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.res.R; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.notification.AnimatableProperty; -import com.android.systemui.statusbar.notification.PropertyAnimator; -import com.android.systemui.statusbar.notification.stack.AnimationProperties; -import com.android.systemui.statusbar.notification.stack.StackStateAnimator; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.ScreenOffAnimationController; -import com.android.systemui.user.data.source.UserRecord; -import com.android.systemui.util.ViewController; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -/** - * Manages the user switcher on the Keyguard. - */ -@KeyguardUserSwitcherScope -@Deprecated -public class KeyguardUserSwitcherController extends ViewController<KeyguardUserSwitcherView> { - - private static final String TAG = "KeyguardUserSwitcherController"; - private static final boolean DEBUG = KeyguardConstants.DEBUG; - - private static final AnimationProperties ANIMATION_PROPERTIES = - new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); - - private final Context mContext; - private final UserSwitcherController mUserSwitcherController; - private final ScreenLifecycle mScreenLifecycle; - private final KeyguardUserAdapter mAdapter; - private final KeyguardStateController mKeyguardStateController; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - protected final SysuiStatusBarStateController mStatusBarStateController; - private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; - private ObjectAnimator mBgAnimator; - private final KeyguardUserSwitcherScrim mBackground; - - // Child views of KeyguardUserSwitcherView - private KeyguardUserSwitcherListView mListView; - - // State info for the user switcher - private boolean mUserSwitcherOpen; - private int mCurrentUserId = UserHandle.USER_NULL; - private int mBarState; - private float mDarkAmount; - - private final KeyguardUpdateMonitorCallback mInfoCallback = - new KeyguardUpdateMonitorCallback() { - @Override - public void onKeyguardVisibilityChanged(boolean visible) { - if (DEBUG) Log.d(TAG, String.format("onKeyguardVisibilityChanged %b", visible)); - // Any time the keyguard is hidden, try to close the user switcher menu to - // restore keyguard to the default state - if (!visible) { - closeSwitcherIfOpenAndNotSimple(false); - } - } - - @Override - public void onUserSwitching(int userId) { - closeSwitcherIfOpenAndNotSimple(false); - } - }; - - private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { - @Override - public void onScreenTurnedOff() { - if (DEBUG) Log.d(TAG, "onScreenTurnedOff"); - closeSwitcherIfOpenAndNotSimple(false); - } - }; - - private final StatusBarStateController.StateListener mStatusBarStateListener = - new StatusBarStateController.StateListener() { - @Override - public void onStateChanged(int newState) { - if (DEBUG) Log.d(TAG, String.format("onStateChanged: newState=%d", newState)); - - boolean goingToFullShade = mStatusBarStateController.goingToFullShade(); - boolean keyguardFadingAway = mKeyguardStateController.isKeyguardFadingAway(); - int oldState = mBarState; - mBarState = newState; - - if (mStatusBarStateController.goingToFullShade() - || mKeyguardStateController.isKeyguardFadingAway()) { - closeSwitcherIfOpenAndNotSimple(true); - } - - setKeyguardUserSwitcherVisibility( - newState, - keyguardFadingAway, - goingToFullShade, - oldState); - } - - @Override - public void onDozeAmountChanged(float linearAmount, float amount) { - if (DEBUG) { - Log.d(TAG, String.format("onDozeAmountChanged: linearAmount=%f amount=%f", - linearAmount, amount)); - } - setDarkAmount(amount); - } - }; - - @Inject - public KeyguardUserSwitcherController( - KeyguardUserSwitcherView keyguardUserSwitcherView, - Context context, - @Main Resources resources, - LayoutInflater layoutInflater, - ScreenLifecycle screenLifecycle, - UserSwitcherController userSwitcherController, - KeyguardStateController keyguardStateController, - SysuiStatusBarStateController statusBarStateController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - DozeParameters dozeParameters, - ScreenOffAnimationController screenOffAnimationController) { - super(keyguardUserSwitcherView); - if (DEBUG) Log.d(TAG, "New KeyguardUserSwitcherController"); - mContext = context; - mScreenLifecycle = screenLifecycle; - mUserSwitcherController = userSwitcherController; - mKeyguardStateController = keyguardStateController; - mStatusBarStateController = statusBarStateController; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mAdapter = new KeyguardUserAdapter(mContext, resources, layoutInflater, - mUserSwitcherController, this); - mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, - keyguardStateController, dozeParameters, - screenOffAnimationController, /* animateYPos= */ false, - /* logBuffer= */ null); - mBackground = new KeyguardUserSwitcherScrim(context); - } - - @Override - protected void onInit() { - super.onInit(); - - if (DEBUG) Log.d(TAG, "onInit"); - - mListView = mView.findViewById(R.id.keyguard_user_switcher_list); - - mView.setOnTouchListener((v, event) -> { - if (!isListAnimating()) { - // Hide switcher if it didn't handle the touch event (and block the event from - // going through). - return closeSwitcherIfOpenAndNotSimple(true); - } - return false; - }); - } - - @Override - protected void onViewAttached() { - if (DEBUG) Log.d(TAG, "onViewAttached"); - mAdapter.registerDataSetObserver(mDataSetObserver); - mAdapter.notifyDataSetChanged(); - mKeyguardUpdateMonitor.registerCallback(mInfoCallback); - mStatusBarStateController.addCallback(mStatusBarStateListener); - mScreenLifecycle.addObserver(mScreenObserver); - if (isSimpleUserSwitcher()) { - // Don't use the background for the simple user switcher - setUserSwitcherOpened(true /* open */, true /* animate */); - } else { - mView.addOnLayoutChangeListener(mBackground); - mView.setBackground(mBackground); - mBackground.setAlpha(0); - } - } - - @Override - protected void onViewDetached() { - if (DEBUG) Log.d(TAG, "onViewDetached"); - - // Detaching the view will always close the switcher - closeSwitcherIfOpenAndNotSimple(false); - - mAdapter.unregisterDataSetObserver(mDataSetObserver); - mKeyguardUpdateMonitor.removeCallback(mInfoCallback); - mStatusBarStateController.removeCallback(mStatusBarStateListener); - mScreenLifecycle.removeObserver(mScreenObserver); - mView.removeOnLayoutChangeListener(mBackground); - mView.setBackground(null); - mBackground.setAlpha(0); - } - - /** - * Returns {@code true} if the user switcher should be open by default on the lock screen. - * - * @see android.os.UserManager#isUserSwitcherEnabled() - */ - public boolean isSimpleUserSwitcher() { - return mUserSwitcherController.isSimpleUserSwitcher(); - } - - public int getHeight() { - return mListView.getHeight(); - } - - /** - * @param animate if the transition should be animated - * @return true if the switcher state changed - */ - public boolean closeSwitcherIfOpenAndNotSimple(boolean animate) { - if (isUserSwitcherOpen() && !isSimpleUserSwitcher()) { - setUserSwitcherOpened(false /* open */, animate); - return true; - } - return false; - } - - public final DataSetObserver mDataSetObserver = new DataSetObserver() { - @Override - public void onChanged() { - refreshUserList(); - } - }; - - void refreshUserList() { - final int childCount = mListView.getChildCount(); - final int adapterCount = mAdapter.getCount(); - final int count = Math.max(childCount, adapterCount); - - if (DEBUG) { - Log.d(TAG, String.format("refreshUserList childCount=%d adapterCount=%d", childCount, - adapterCount)); - } - - boolean foundCurrentUser = false; - for (int i = 0; i < count; i++) { - if (i < adapterCount) { - View oldView = null; - if (i < childCount) { - oldView = mListView.getChildAt(i); - } - KeyguardUserDetailItemView newView = (KeyguardUserDetailItemView) - mAdapter.getView(i, oldView, mListView); - UserRecord userTag = - (UserRecord) newView.getTag(); - if (userTag.isCurrent) { - if (i != 0) { - Log.w(TAG, "Current user is not the first view in the list"); - } - foundCurrentUser = true; - mCurrentUserId = userTag.info.id; - // Current user is always visible - newView.updateVisibilities(true /* showItem */, - mUserSwitcherOpen /* showTextName */, false /* animate */); - } else { - // Views for non-current users are always expanded (e.g. they should the name - // next to the user icon). However, they could be hidden entirely if the list - // is closed. - newView.updateVisibilities(mUserSwitcherOpen /* showItem */, - true /* showTextName */, false /* animate */); - } - newView.setDarkAmount(mDarkAmount); - if (oldView == null) { - // We ran out of existing views. Add it at the end. - mListView.addView(newView); - } else if (oldView != newView) { - // We couldn't rebind the view. Replace it. - mListView.replaceView(newView, i); - } - } else { - mListView.removeLastView(); - } - } - if (!foundCurrentUser) { - Log.w(TAG, "Current user is not listed"); - mCurrentUserId = UserHandle.USER_NULL; - } - } - - /** - * Set the visibility of the keyguard user switcher view based on some new state. - */ - public void setKeyguardUserSwitcherVisibility( - int statusBarState, - boolean keyguardFadingAway, - boolean goingToFullShade, - int oldStatusBarState) { - mKeyguardVisibilityHelper.setViewVisibility( - statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState); - } - - /** - * Update position of the view with an optional animation - */ - public void updatePosition(int x, int y, boolean animate) { - PropertyAnimator.setProperty(mListView, AnimatableProperty.Y, y, ANIMATION_PROPERTIES, - animate); - PropertyAnimator.setProperty(mListView, AnimatableProperty.TRANSLATION_X, -Math.abs(x), - ANIMATION_PROPERTIES, animate); - - Rect r = new Rect(); - mListView.getDrawingRect(r); - mView.offsetDescendantRectToMyCoords(mListView, r); - mBackground.setGradientCenter( - (int) (mListView.getTranslationX() + r.left + r.width() / 2), - (int) (mListView.getTranslationY() + r.top + r.height() / 2)); - } - - /** - * Set keyguard user switcher view alpha. - */ - public void setAlpha(float alpha) { - if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) { - mView.setAlpha(alpha); - } - } - - /** - * Set the amount (ratio) that the device has transitioned to doze. - * - * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. - */ - private void setDarkAmount(float darkAmount) { - boolean isFullyDozed = darkAmount == 1; - if (darkAmount == mDarkAmount) { - return; - } - mDarkAmount = darkAmount; - mListView.setDarkAmount(darkAmount); - if (isFullyDozed) { - closeSwitcherIfOpenAndNotSimple(false); - } - } - - private boolean isListAnimating() { - return mKeyguardVisibilityHelper.isVisibilityAnimating() || mListView.isAnimating(); - } - - /** - * NOTE: switcher state is updated before animations finish. - * - * @param animate true to animate transition. The user switcher state (i.e. - * {@link #isUserSwitcherOpen()}) is updated before animation is finished. - */ - private void setUserSwitcherOpened(boolean open, boolean animate) { - if (DEBUG) { - Log.d(TAG, - String.format("setUserSwitcherOpened: %b -> %b (animate=%b)", - mUserSwitcherOpen, open, animate)); - } - mUserSwitcherOpen = open; - updateVisibilities(animate); - } - - private void updateVisibilities(boolean animate) { - if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate)); - if (mBgAnimator != null) { - mBgAnimator.cancel(); - } - - if (mUserSwitcherOpen) { - mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255); - mBgAnimator.setDuration(400); - mBgAnimator.setInterpolator(Interpolators.ALPHA_IN); - mBgAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBgAnimator = null; - } - }); - mBgAnimator.start(); - } else { - mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 255, 0); - mBgAnimator.setDuration(400); - mBgAnimator.setInterpolator(Interpolators.ALPHA_OUT); - mBgAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBgAnimator = null; - } - }); - mBgAnimator.start(); - } - mListView.updateVisibilities(mUserSwitcherOpen, animate); - } - - private boolean isUserSwitcherOpen() { - return mUserSwitcherOpen; - } - - static class KeyguardUserAdapter extends - BaseUserSwitcherAdapter implements View.OnClickListener { - - private final Context mContext; - private final Resources mResources; - private final LayoutInflater mLayoutInflater; - private KeyguardUserSwitcherController mKeyguardUserSwitcherController; - private View mCurrentUserView; - // List of users where the first entry is always the current user - private ArrayList<UserRecord> mUsersOrdered = new ArrayList<>(); - - KeyguardUserAdapter(Context context, Resources resources, LayoutInflater layoutInflater, - UserSwitcherController controller, - KeyguardUserSwitcherController keyguardUserSwitcherController) { - super(controller); - mContext = context; - mResources = resources; - mLayoutInflater = layoutInflater; - mKeyguardUserSwitcherController = keyguardUserSwitcherController; - } - - @Override - public void notifyDataSetChanged() { - // At this point, value of isSimpleUserSwitcher() may have changed in addition to the - // data set - refreshUserOrder(); - super.notifyDataSetChanged(); - } - - void refreshUserOrder() { - List<UserRecord> users = super.getUsers(); - mUsersOrdered = new ArrayList<>(users.size()); - for (int i = 0; i < users.size(); i++) { - UserRecord record = users.get(i); - if (record.isCurrent) { - mUsersOrdered.add(0, record); - } else { - mUsersOrdered.add(record); - } - } - } - - @Override - protected ArrayList<UserRecord> getUsers() { - return mUsersOrdered; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - UserRecord item = getItem(position); - return createUserDetailItemView(convertView, parent, item); - } - - KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) { - if (!(convertView instanceof KeyguardUserDetailItemView) - || !(convertView.getTag() instanceof UserRecord)) { - convertView = mLayoutInflater.inflate( - R.layout.keyguard_user_switcher_item, parent, false); - } - return (KeyguardUserDetailItemView) convertView; - } - - KeyguardUserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent, - UserRecord item) { - KeyguardUserDetailItemView v = convertOrInflate(convertView, parent); - v.setOnClickListener(this); - - String name = getName(mContext, item); - if (item.picture == null) { - v.bind(name, getDrawable(item).mutate(), item.resolveId()); - } else { - int avatarSize = - (int) mResources.getDimension(R.dimen.kg_framed_avatar_size); - Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize); - drawable.setColorFilter( - item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); - v.bind(name, drawable, item.info.id); - } - v.setActivated(item.isCurrent); - v.setDisabledByAdmin(item.isDisabledByAdmin()); - v.setEnabled(item.isSwitchToEnabled); - UserSwitcherController.setSelectableAlpha(v); - - if (item.isCurrent) { - mCurrentUserView = v; - } - v.setTag(item); - return v; - } - - private Drawable getDrawable(UserRecord item) { - Drawable drawable; - if (item.isCurrent && item.isGuest) { - drawable = mContext.getDrawable(R.drawable.ic_avatar_guest_user); - } else { - drawable = getIconDrawable(mContext, item); - } - - int iconColorRes; - if (item.isSwitchToEnabled) { - iconColorRes = R.color.kg_user_switcher_avatar_icon_color; - } else { - iconColorRes = R.color.kg_user_switcher_restricted_avatar_icon_color; - } - drawable.setTint(mResources.getColor(iconColorRes, mContext.getTheme())); - - Drawable bg = mContext.getDrawable(com.android.settingslib.R.drawable.user_avatar_bg); - drawable = new LayerDrawable(new Drawable[]{bg, drawable}); - return drawable; - } - - @Override - public void onClick(View v) { - UserRecord user = (UserRecord) v.getTag(); - - if (mKeyguardUserSwitcherController.isListAnimating()) { - return; - } - - if (mKeyguardUserSwitcherController.isUserSwitcherOpen()) { - if (!user.isCurrent || user.isGuest) { - onUserListItemClicked(user); - } else { - mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( - true /* animate */); - } - } else { - // If switcher is closed, tapping anywhere in the view will open it - mKeyguardUserSwitcherController.setUserSwitcherOpened( - true /* open */, true /* animate */); - } - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java deleted file mode 100644 index 363b06ab780b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import com.android.app.animation.Interpolators; -import com.android.keyguard.AlphaOptimizedLinearLayout; -import com.android.keyguard.KeyguardConstants; -import com.android.settingslib.animation.AppearAnimationUtils; -import com.android.settingslib.animation.DisappearAnimationUtils; - -/** - * The container for the user switcher on Keyguard. - */ -public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { - - private static final String TAG = "KeyguardUserSwitcherListView"; - private static final boolean DEBUG = KeyguardConstants.DEBUG; - - private boolean mAnimating; - private final AppearAnimationUtils mAppearAnimationUtils; - private final DisappearAnimationUtils mDisappearAnimationUtils; - - public KeyguardUserSwitcherListView(Context context, AttributeSet attrs) { - super(context, attrs); - mAppearAnimationUtils = new AppearAnimationUtils(context, - AppearAnimationUtils.DEFAULT_APPEAR_DURATION, - -0.5f /* translationScaleFactor */, - 0.5f /* delayScaleFactor */, - Interpolators.FAST_OUT_SLOW_IN); - mDisappearAnimationUtils = new DisappearAnimationUtils(context, - AppearAnimationUtils.DEFAULT_APPEAR_DURATION, - 0.2f /* translationScaleFactor */, - 0.2f /* delayScaleFactor */, - Interpolators.FAST_OUT_SLOW_IN_REVERSE); - } - - /** - * Set the amount (ratio) that the device has transitioned to doze. - * - * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. - */ - void setDarkAmount(float darkAmount) { - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View v = getChildAt(i); - if (v instanceof KeyguardUserDetailItemView) { - ((KeyguardUserDetailItemView) v).setDarkAmount(darkAmount); - } - } - } - - boolean isAnimating() { - return mAnimating; - } - - /** - * Update visibilities of this view and child views for when the user list is open or closed. - * If closed, this hides everything but the first item (which is always the current user). - */ - void updateVisibilities(boolean open, boolean animate) { - if (DEBUG) { - Log.d(TAG, String.format("updateVisibilities: open=%b animate=%b childCount=%d", - open, animate, getChildCount())); - } - - mAnimating = false; - - int childCount = getChildCount(); - KeyguardUserDetailItemView[] userItemViews = new KeyguardUserDetailItemView[childCount]; - for (int i = 0; i < childCount; i++) { - userItemViews[i] = (KeyguardUserDetailItemView) getChildAt(i); - userItemViews[i].clearAnimation(); - if (i == 0) { - // The first child is always the current user. - userItemViews[i].updateVisibilities(true /* showItem */, open /* showTextName */, - animate); - userItemViews[i].setClickable(true); - } else { - // Update clickable state immediately so that the menu feels more responsive - userItemViews[i].setClickable(open); - // when opening we need to make views visible beforehand so they can be animated - if (open) { - userItemViews[i].updateVisibilities(true /* showItem */, - true /* showTextName */, false /* animate */); - } - - } - } - - if (animate && userItemViews.length > 1) { - // AnimationUtils will immediately hide/show the first item in the array. Since the - // first view is the current user, we want to manage its visibility separately. - // Set first item to null so AnimationUtils ignores it. - userItemViews[0] = null; - - setClipChildren(false); - setClipToPadding(false); - mAnimating = true; - (open ? mAppearAnimationUtils : mDisappearAnimationUtils) - .startAnimation(userItemViews, () -> { - setClipChildren(true); - setClipToPadding(true); - mAnimating = false; - if (!open) { - // after closing we hide children so that height of this view is correct - for (int i = 1; i < userItemViews.length; i++) { - userItemViews[i].updateVisibilities(false /* showItem */, - true /* showTextName */, false /* animate */); - } - } - }); - } - } - - /** - * Replaces the view at the specified position in the group. - * - * @param index the position in the group of the view to remove - */ - void replaceView(KeyguardUserDetailItemView newView, int index) { - removeViewAt(index); - addView(newView, index); - } - - /** - * Removes the last view in the group. - */ - void removeLastView() { - int lastIndex = getChildCount() - 1; - removeViewAt(lastIndex); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java deleted file mode 100644 index 5ed207cc3447..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.policy; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.RadialGradient; -import android.graphics.Rect; -import android.graphics.Shader; -import android.graphics.drawable.Drawable; -import android.view.View; - -import com.android.systemui.res.R; - -/** - * Gradient background for the user switcher on Keyguard. - */ -public class KeyguardUserSwitcherScrim extends Drawable - implements View.OnLayoutChangeListener { - - private static final float OUTER_EXTENT = 2.5f; - private static final float INNER_EXTENT = 0.25f; - - private int mDarkColor; - private int mAlpha = 255; - private Paint mRadialGradientPaint = new Paint(); - private int mCircleX; - private int mCircleY; - private int mSize; - - public KeyguardUserSwitcherScrim(Context context) { - mDarkColor = context.getColor( - R.color.keyguard_user_switcher_background_gradient_color); - } - - @Override - public void draw(Canvas canvas) { - if (mAlpha == 0) { - return; - } - Rect bounds = getBounds(); - canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.bottom, mRadialGradientPaint); - } - - @Override - public void setAlpha(int alpha) { - mAlpha = alpha; - updatePaint(); - invalidateSelf(); - } - - @Override - public int getAlpha() { - return mAlpha; - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, - int oldTop, int oldRight, int oldBottom) { - if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) { - int width = right - left; - int height = bottom - top; - mSize = Math.max(width, height); - updatePaint(); - } - } - - private void updatePaint() { - if (mSize == 0) { - return; - } - float outerRadius = mSize * OUTER_EXTENT; - mRadialGradientPaint.setShader( - new RadialGradient(mCircleX, mCircleY, outerRadius, - new int[] { Color.argb( - (int) (Color.alpha(mDarkColor) * mAlpha / 255f), 0, 0, 0), - Color.TRANSPARENT }, - new float[] { Math.max(0f, INNER_EXTENT / OUTER_EXTENT), 1f }, - Shader.TileMode.CLAMP)); - } - - /** - * Sets the center of the radial gradient used as a background - * - * @param x - * @param y - */ - public void setGradientCenter(int x, int y) { - mCircleX = x; - mCircleY = y; - updatePaint(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegate.kt index a1d5cbea62f9..9ff0d18f0e2b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegate.kt @@ -44,6 +44,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dialog.ui.composable.AlertDialogContent import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.ComponentSystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialogFactory @@ -67,6 +68,7 @@ constructor( private val viewModel: Provider<ModesDialogViewModel>, private val dialogEventLogger: ModesDialogEventLogger, @Main private val mainCoroutineContext: CoroutineContext, + private val shadeDisplayContextRepository: ShadeDialogContextInteractor, ) : SystemUIDialog.Delegate { // NOTE: This should only be accessed/written from the main thread. @VisibleForTesting var currentDialog: ComponentSystemUIDialog? = null @@ -78,7 +80,10 @@ constructor( currentDialog?.dismiss() } - currentDialog = sysuiDialogFactory.create { ModesDialogContent(it) } + currentDialog = + sysuiDialogFactory.create(context = shadeDisplayContextRepository.context) { + ModesDialogContent(it) + } currentDialog ?.lifecycle ?.addObserver( @@ -106,9 +111,8 @@ constructor( modifier = Modifier.semantics { testTagsAsResourceId = true - paneTitle = dialog.context.getString( - R.string.accessibility_desc_quick_settings - ) + paneTitle = + dialog.context.getString(R.string.accessibility_desc_quick_settings) }, title = { Text( diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt index 3fa3f638a340..fbf7072cc0a0 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt @@ -27,7 +27,11 @@ import com.android.systemui.settings.DisplayTracker import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen +import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker +import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker import com.android.systemui.touchpad.tutorial.ui.view.TouchpadTutorialActivity +import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureScreenViewModel +import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureScreenViewModel import dagger.Binds import dagger.Module import dagger.Provides @@ -45,8 +49,11 @@ interface TouchpadTutorialModule { companion object { @Provides - fun touchpadScreensProvider(): TouchpadTutorialScreensProvider { - return ScreensProvider + fun touchpadScreensProvider( + backGestureScreenViewModel: BackGestureScreenViewModel, + homeGestureScreenViewModel: HomeGestureScreenViewModel, + ): TouchpadTutorialScreensProvider { + return ScreensProvider(backGestureScreenViewModel, homeGestureScreenViewModel) } @SysUISingleton @@ -59,17 +66,22 @@ interface TouchpadTutorialModule { ): TouchpadGesturesInteractor { return TouchpadGesturesInteractor(sysUiState, displayTracker, backgroundScope, logger) } + + @Provides fun velocityTracker(): VelocityTracker = VerticalVelocityTracker() } } -private object ScreensProvider : TouchpadTutorialScreensProvider { +private class ScreensProvider( + val backGestureScreenViewModel: BackGestureScreenViewModel, + val homeGestureScreenViewModel: HomeGestureScreenViewModel, +) : TouchpadTutorialScreensProvider { @Composable override fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { - BackGestureTutorialScreen(onDoneButtonClicked, onBack) + BackGestureTutorialScreen(backGestureScreenViewModel, onDoneButtonClicked, onBack) } @Composable override fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { - HomeGestureTutorialScreen(onDoneButtonClicked, onBack) + HomeGestureTutorialScreen(homeGestureScreenViewModel, onDoneButtonClicked, onBack) } } diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt index e1cc11a7cfd1..804a764b5349 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt @@ -16,26 +16,22 @@ package com.android.systemui.touchpad.tutorial.ui.composable -import android.content.res.Resources import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import com.airbnb.lottie.compose.rememberLottieDynamicProperties import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R -import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureDirection -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState -import com.android.systemui.util.kotlin.pairwiseBy -import kotlinx.coroutines.flow.Flow +import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureScreenViewModel @Composable -fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { +fun BackGestureTutorialScreen( + viewModel: BackGestureScreenViewModel, + onDoneButtonClicked: () -> Unit, + onBack: () -> Unit, +) { val screenConfig = TutorialScreenConfig( colors = rememberScreenColors(), @@ -50,40 +46,15 @@ fun BackGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Uni ), animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_back_edu), ) - val recognizer = rememberBackGestureRecognizer(LocalContext.current.resources) - val gestureUiState: Flow<GestureUiState> = - remember(recognizer) { - GestureFlowAdapter(recognizer).gestureStateAsFlow.pairwiseBy(GestureState.NotStarted) { - previous, - current -> - val (startMarker, endMarker) = getMarkers(current) - current.toGestureUiState( - progressStartMarker = startMarker, - progressEndMarker = endMarker, - successAnimation = successAnimation(previous), - ) - } - } - GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) -} - -@Composable -private fun rememberBackGestureRecognizer(resources: Resources): GestureRecognizer { - val distance = - resources.getDimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold) - return remember(distance) { BackGestureRecognizer(distance) } -} - -private fun getMarkers(it: GestureState): Pair<String, String> { - return if (it is GestureState.InProgress && it.direction == GestureDirection.LEFT) { - "gesture to L" to "end progress L" - } else "gesture to R" to "end progress R" -} - -private fun successAnimation(previous: GestureState): Int { - return if (previous is GestureState.InProgress && previous.direction == GestureDirection.LEFT) { - R.raw.trackpad_back_success_left - } else R.raw.trackpad_back_success_right + GestureTutorialScreen( + screenConfig = screenConfig, + gestureUiStateFlow = viewModel.gestureUiState, + motionEventConsumer = viewModel::handleEvent, + easterEggTriggeredFlow = viewModel.easterEggTriggered, + onEasterEggFinished = viewModel::onEasterEggFinished, + onDoneButtonClicked = onDoneButtonClicked, + onBack = onBack, + ) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt index ed84f9c42c3a..73c54af595d9 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt @@ -16,6 +16,7 @@ package com.android.systemui.touchpad.tutorial.ui.composable +import android.view.MotionEvent import androidx.activity.compose.BackHandler import androidx.annotation.RawRes import androidx.compose.animation.core.Animatable @@ -38,10 +39,7 @@ import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionSta import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.NotStarted -import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState -import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler import kotlinx.coroutines.flow.Flow sealed interface GestureUiState { @@ -99,22 +97,21 @@ fun GestureUiState.toTutorialActionState(previousState: TutorialActionState): Tu @Composable fun GestureTutorialScreen( screenConfig: TutorialScreenConfig, - gestureRecognizer: GestureRecognizer, gestureUiStateFlow: Flow<GestureUiState>, + motionEventConsumer: (MotionEvent) -> Boolean, + easterEggTriggeredFlow: Flow<Boolean>, + onEasterEggFinished: () -> Unit, onDoneButtonClicked: () -> Unit, onBack: () -> Unit, ) { BackHandler(onBack = onBack) - var easterEggTriggered by remember { mutableStateOf(false) } + val easterEggTriggered by easterEggTriggeredFlow.collectAsStateWithLifecycle(false) val gestureState by gestureUiStateFlow.collectAsStateWithLifecycle(NotStarted) - val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered = true } - val gestureHandler = - remember(gestureRecognizer) { TouchpadGestureHandler(gestureRecognizer, easterEggMonitor) } TouchpadGesturesHandlingBox( - gestureHandler, + motionEventConsumer, gestureState, easterEggTriggered, - resetEasterEggFlag = { easterEggTriggered = false }, + onEasterEggFinished, ) { var lastState: TutorialActionState by remember { mutableStateOf(TutorialActionState.NotStarted) @@ -126,10 +123,10 @@ fun GestureTutorialScreen( @Composable private fun TouchpadGesturesHandlingBox( - gestureHandler: TouchpadGestureHandler, + motionEventConsumer: (MotionEvent) -> Boolean, gestureState: GestureUiState, easterEggTriggered: Boolean, - resetEasterEggFlag: () -> Unit, + onEasterEggFinished: () -> Unit, modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit, ) { @@ -141,7 +138,7 @@ private fun TouchpadGesturesHandlingBox( targetValue = 360f, animationSpec = tween(durationMillis = 2000), ) - resetEasterEggFlag() + onEasterEggFinished() } } Box( @@ -156,7 +153,7 @@ private fun TouchpadGesturesHandlingBox( if (gestureState is Finished) { false } else { - gestureHandler.onMotionEvent(event) + motionEventConsumer(event) } } ) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt index 26604ca6b845..5dcd788ea4fd 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt @@ -16,23 +16,21 @@ package com.android.systemui.touchpad.tutorial.ui.composable -import android.content.res.Resources import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import com.airbnb.lottie.compose.rememberLottieDynamicProperties import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer -import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map +import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureScreenViewModel @Composable -fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { +fun HomeGestureTutorialScreen( + viewModel: HomeGestureScreenViewModel, + onDoneButtonClicked: () -> Unit, + onBack: () -> Unit, +) { val screenConfig = TutorialScreenConfig( colors = rememberScreenColors(), @@ -47,26 +45,15 @@ fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Uni ), animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_home_edu), ) - val recognizer = rememberHomeGestureRecognizer(LocalContext.current.resources) - val gestureUiState: Flow<GestureUiState> = - remember(recognizer) { - GestureFlowAdapter(recognizer).gestureStateAsFlow.map { - it.toGestureUiState( - progressStartMarker = "drag with gesture", - progressEndMarker = "release playback realtime", - successAnimation = R.raw.trackpad_home_success, - ) - } - } - GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) -} - -@Composable -private fun rememberHomeGestureRecognizer(resources: Resources): GestureRecognizer { - val distance = - resources.getDimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold) - val velocity = resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold) - return remember(distance) { HomeGestureRecognizer(distance, velocity) } + GestureTutorialScreen( + screenConfig = screenConfig, + gestureUiStateFlow = viewModel.gestureUiState, + motionEventConsumer = viewModel::handleEvent, + easterEggTriggeredFlow = viewModel.easterEggTriggered, + onEasterEggFinished = viewModel::onEasterEggFinished, + onDoneButtonClicked = onDoneButtonClicked, + onBack = onBack, + ) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt index 6400aca57693..7ff838981950 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt @@ -16,23 +16,21 @@ package com.android.systemui.touchpad.tutorial.ui.composable -import android.content.res.Resources import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalContext import com.airbnb.lottie.compose.rememberLottieDynamicProperties import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty import com.android.systemui.res.R -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter -import com.android.systemui.touchpad.tutorial.ui.gesture.GestureRecognizer -import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map +import com.android.systemui.touchpad.tutorial.ui.viewmodel.RecentAppsGestureScreenViewModel @Composable -fun RecentAppsGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { +fun RecentAppsGestureTutorialScreen( + viewModel: RecentAppsGestureScreenViewModel, + onDoneButtonClicked: () -> Unit, + onBack: () -> Unit, +) { val screenConfig = TutorialScreenConfig( colors = rememberScreenColors(), @@ -48,26 +46,15 @@ fun RecentAppsGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_recent_apps_edu), ) - val recognizer = rememberRecentAppsGestureRecognizer(LocalContext.current.resources) - val gestureUiState: Flow<GestureUiState> = - remember(recognizer) { - GestureFlowAdapter(recognizer).gestureStateAsFlow.map { - it.toGestureUiState( - progressStartMarker = "drag with gesture", - progressEndMarker = "onPause", - successAnimation = R.raw.trackpad_recent_apps_success, - ) - } - } - GestureTutorialScreen(screenConfig, recognizer, gestureUiState, onDoneButtonClicked, onBack) -} - -@Composable -private fun rememberRecentAppsGestureRecognizer(resources: Resources): GestureRecognizer { - val distance = - resources.getDimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold) - val velocity = resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold) - return remember(distance, velocity) { RecentAppsGestureRecognizer(distance, velocity) } + GestureTutorialScreen( + screenConfig = screenConfig, + gestureUiStateFlow = viewModel.gestureUiState, + motionEventConsumer = viewModel::handleEvent, + easterEggTriggeredFlow = viewModel.easterEggTriggered, + onEasterEggFinished = viewModel::onEasterEggFinished, + onDoneButtonClicked = onDoneButtonClicked, + onBack = onBack, + ) } @Composable diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt index 6662fc5c127c..6b4cbab3ae09 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt @@ -38,6 +38,9 @@ import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialS import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen +import com.android.systemui.touchpad.tutorial.ui.viewmodel.BackGestureScreenViewModel +import com.android.systemui.touchpad.tutorial.ui.viewmodel.HomeGestureScreenViewModel +import com.android.systemui.touchpad.tutorial.ui.viewmodel.RecentAppsGestureScreenViewModel import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.BACK_GESTURE import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.HOME_GESTURE import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.RECENT_APPS_GESTURE @@ -51,16 +54,28 @@ constructor( private val viewModelFactory: TouchpadTutorialViewModel.Factory, private val logger: InputDeviceTutorialLogger, private val metricsLogger: KeyboardTouchpadTutorialMetricsLogger, + private val backGestureViewModel: BackGestureScreenViewModel, + private val homeGestureViewModel: HomeGestureScreenViewModel, + private val recentAppsGestureViewModel: RecentAppsGestureScreenViewModel, ) : ComponentActivity() { - private val vm by viewModels<TouchpadTutorialViewModel>(factoryProducer = { viewModelFactory }) + private val tutorialViewModel by + viewModels<TouchpadTutorialViewModel>(factoryProducer = { viewModelFactory }) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setTitle(getString(R.string.launch_touchpad_tutorial_notification_content)) setContent { - PlatformTheme { TouchpadTutorialScreen(vm, closeTutorial = ::finishTutorial) } + PlatformTheme { + TouchpadTutorialScreen( + tutorialViewModel, + backGestureViewModel, + homeGestureViewModel, + recentAppsGestureViewModel, + closeTutorial = ::finishTutorial, + ) + } } // required to handle 3+ fingers on touchpad window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY) @@ -75,17 +90,23 @@ constructor( override fun onResume() { super.onResume() - vm.onOpened() + tutorialViewModel.onOpened() } override fun onPause() { super.onPause() - vm.onClosed() + tutorialViewModel.onClosed() } } @Composable -fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> Unit) { +fun TouchpadTutorialScreen( + vm: TouchpadTutorialViewModel, + backGestureViewModel: BackGestureScreenViewModel, + homeGestureViewModel: HomeGestureScreenViewModel, + recentAppsGestureViewModel: RecentAppsGestureScreenViewModel, + closeTutorial: () -> Unit, +) { val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED) var lastSelectedScreen by remember { mutableStateOf(TUTORIAL_SELECTION) } when (activeScreen) { @@ -108,16 +129,19 @@ fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> U ) BACK_GESTURE -> BackGestureTutorialScreen( + backGestureViewModel, onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) }, onBack = { vm.goTo(TUTORIAL_SELECTION) }, ) HOME_GESTURE -> HomeGestureTutorialScreen( + homeGestureViewModel, onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) }, onBack = { vm.goTo(TUTORIAL_SELECTION) }, ) RECENT_APPS_GESTURE -> RecentAppsGestureTutorialScreen( + recentAppsGestureViewModel, onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) }, onBack = { vm.goTo(TUTORIAL_SELECTION) }, ) diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt new file mode 100644 index 000000000000..0154c910be91 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/BackGestureScreenViewModel.kt @@ -0,0 +1,86 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.view.MotionEvent +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.res.R +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState +import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureRecognizer +import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureDirection +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress +import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler +import com.android.systemui.util.kotlin.pairwiseBy +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest + +class BackGestureScreenViewModel +@Inject +constructor(configurationInteractor: ConfigurationInteractor) : TouchpadTutorialScreenViewModel { + + private val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered.value = true } + override val easterEggTriggered = MutableStateFlow(false) + + private var handler: TouchpadGestureHandler? = null + + private val distanceThreshold: Flow<Int> = + configurationInteractor + .dimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold) + .distinctUntilChanged() + + @OptIn(ExperimentalCoroutinesApi::class) + override val gestureUiState: Flow<GestureUiState> = + distanceThreshold + .flatMapLatest { + val recognizer = BackGestureRecognizer(gestureDistanceThresholdPx = it) + handler = TouchpadGestureHandler(recognizer, easterEggMonitor) + GestureFlowAdapter(recognizer).gestureStateAsFlow + } + .pairwiseBy(GestureState.NotStarted) { previous, current -> + toGestureUiState(current, previous) + } + + override fun handleEvent(event: MotionEvent): Boolean { + return handler?.onMotionEvent(event) ?: false + } + + private fun toGestureUiState(current: GestureState, previous: GestureState): GestureUiState { + val (startMarker, endMarker) = + if (current is InProgress && current.direction == GestureDirection.LEFT) { + "gesture to L" to "end progress L" + } else "gesture to R" to "end progress R" + return current.toGestureUiState( + progressStartMarker = startMarker, + progressEndMarker = endMarker, + successAnimation = successAnimation(previous), + ) + } + + private fun successAnimation(previous: GestureState): Int { + return if (previous is InProgress && previous.direction == GestureDirection.LEFT) { + R.raw.trackpad_back_success_left + } else R.raw.trackpad_back_success_right + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt new file mode 100644 index 000000000000..1c865f57b8c7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/HomeGestureScreenViewModel.kt @@ -0,0 +1,91 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.content.res.Resources +import android.view.MotionEvent +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.res.R +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState +import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState +import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureRecognizer +import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler +import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker +import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map + +class HomeGestureScreenViewModel +@Inject +constructor( + val configurationInteractor: ConfigurationInteractor, + @Main val resources: Resources, + val velocityTracker: VelocityTracker = VerticalVelocityTracker(), +) : TouchpadTutorialScreenViewModel { + + private val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered.value = true } + override val easterEggTriggered = MutableStateFlow(false) + + private var handler: TouchpadGestureHandler? = null + + private val distanceThreshold: Flow<Int> = + configurationInteractor + .dimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold) + .distinctUntilChanged() + + private val velocityThreshold: Flow<Float> = + configurationInteractor.onAnyConfigurationChange + .map { resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold) } + .distinctUntilChanged() + + @OptIn(ExperimentalCoroutinesApi::class) + override val gestureUiState: Flow<GestureUiState> = + distanceThreshold + .combine(velocityThreshold, { distance, velocity -> distance to velocity }) + .flatMapLatest { (distance, velocity) -> + val recognizer = + HomeGestureRecognizer( + gestureDistanceThresholdPx = distance, + velocityThresholdPxPerMs = velocity, + velocityTracker = velocityTracker, + ) + handler = TouchpadGestureHandler(recognizer, easterEggMonitor) + GestureFlowAdapter(recognizer).gestureStateAsFlow + } + .map { toGestureUiState(it) } + + private fun toGestureUiState(it: GestureState) = + it.toGestureUiState( + progressStartMarker = "drag with gesture", + progressEndMarker = "release playback realtime", + successAnimation = R.raw.trackpad_home_success, + ) + + override fun handleEvent(event: MotionEvent): Boolean { + return handler?.onMotionEvent(event) ?: false + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt new file mode 100644 index 000000000000..09947a8b109e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/RecentAppsGestureScreenViewModel.kt @@ -0,0 +1,95 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.content.res.Resources +import android.view.MotionEvent +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.res.R +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState +import com.android.systemui.touchpad.tutorial.ui.gesture.EasterEggGestureMonitor +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureFlowAdapter +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState +import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureRecognizer +import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler +import com.android.systemui.touchpad.tutorial.ui.gesture.VelocityTracker +import com.android.systemui.touchpad.tutorial.ui.gesture.VerticalVelocityTracker +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map + +class RecentAppsGestureScreenViewModel +@Inject +constructor( + configurationInteractor: ConfigurationInteractor, + @Main private val resources: Resources, + private val velocityTracker: VelocityTracker = VerticalVelocityTracker(), +) : TouchpadTutorialScreenViewModel { + + private val easterEggMonitor = EasterEggGestureMonitor { easterEggTriggered.value = true } + override val easterEggTriggered = MutableStateFlow(false) + + private var handler: TouchpadGestureHandler? = null + + private val distanceThreshold: Flow<Int> = + configurationInteractor.onAnyConfigurationChange + .map { + resources.getDimensionPixelSize( + R.dimen.touchpad_tutorial_gestures_distance_threshold + ) + } + .distinctUntilChanged() + + private val velocityThreshold: Flow<Float> = + configurationInteractor.onAnyConfigurationChange + .map { resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold) } + .distinctUntilChanged() + + @OptIn(ExperimentalCoroutinesApi::class) + override val gestureUiState: Flow<GestureUiState> = + distanceThreshold + .combine(velocityThreshold, { distance, velocity -> distance to velocity }) + .flatMapLatest { (distance, velocity) -> + val recognizer = + RecentAppsGestureRecognizer( + gestureDistanceThresholdPx = distance, + velocityThresholdPxPerMs = velocity, + velocityTracker = velocityTracker, + ) + handler = TouchpadGestureHandler(recognizer, easterEggMonitor) + GestureFlowAdapter(recognizer).gestureStateAsFlow + } + .map { toGestureUiState(it) } + + private fun toGestureUiState(it: GestureState) = + it.toGestureUiState( + progressStartMarker = "drag with gesture", + progressEndMarker = "onPause", + successAnimation = R.raw.trackpad_recent_apps_success, + ) + + override fun handleEvent(event: MotionEvent): Boolean { + return handler?.onMotionEvent(event) ?: false + } +} diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialScreenViewModel.kt new file mode 100644 index 000000000000..500f6a0238c3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialScreenViewModel.kt @@ -0,0 +1,33 @@ +/* + * 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.touchpad.tutorial.ui.viewmodel + +import android.view.MotionEvent +import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +interface TouchpadTutorialScreenViewModel { + val gestureUiState: Flow<GestureUiState> + val easterEggTriggered: MutableStateFlow<Boolean> + + fun onEasterEggFinished() { + easterEggTriggered.value = false + } + + fun handleEvent(event: MotionEvent): Boolean +} diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index a382cf921152..e08114f6c3cd 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -21,10 +21,8 @@ import android.content.Context import android.hardware.devicestate.DeviceStateManager import android.os.PowerManager import android.provider.Settings -import androidx.core.view.OneShotPreDrawListener import com.android.internal.util.LatencyTracker import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.ToAodFoldTransitionInteractor @@ -125,11 +123,7 @@ constructor( private val shadeFoldAnimator: ShadeFoldAnimator get() { - return if (MigrateClocksToBlueprint.isEnabled) { - foldTransitionInteractor.get().foldAnimator - } else { - shadeViewController.shadeFoldAnimator - } + return foldTransitionInteractor.get().foldAnimator } private fun setAnimationState(playing: Boolean) { @@ -164,15 +158,7 @@ constructor( setAnimationState(playing = true) shadeFoldAnimator.prepareFoldToAodAnimation() - // We don't need to wait for the scrim as it is already displayed - // but we should wait for the initial animation preparations to be drawn - // (setting initial alpha/translation) - // TODO(b/254878364): remove this call to NPVC.getView() - if (!MigrateClocksToBlueprint.isEnabled) { - shadeFoldAnimator.view?.let { OneShotPreDrawListener.add(it, onReady) } - } else { - onReady.run() - } + onReady.run() } else { // No animation, call ready callback immediately onReady.run() @@ -252,7 +238,7 @@ constructor( if (isFolded) { foldToAodLatencyTracker.onFolded() } - } + }, ) /** @@ -272,6 +258,7 @@ constructor( latencyTracker.onActionStart(LatencyTracker.ACTION_FOLD_TO_AOD) } } + /** * Called once the Fold -> AOD animation is started. * diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt index 102fcc0c59f2..e4b2dc25e411 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt @@ -18,7 +18,6 @@ package com.android.systemui.user.ui.dialog import android.app.Dialog -import android.content.Context import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.UiEventLogger import com.android.settingslib.users.UserCreatingDialog @@ -32,6 +31,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.tiles.UserDetailView +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.user.UserSwitchFullscreenDialog import com.android.systemui.user.domain.interactor.UserSwitcherInteractor import com.android.systemui.user.domain.model.ShowDialogRequestModel @@ -48,7 +48,6 @@ import com.android.app.tracing.coroutines.launchTraced as launch class UserSwitcherDialogCoordinator @Inject constructor( - @Application private val context: Lazy<Context>, @Application private val applicationScope: Lazy<CoroutineScope>, private val falsingManager: Lazy<FalsingManager>, private val broadcastSender: Lazy<BroadcastSender>, @@ -59,6 +58,7 @@ constructor( private val activityStarter: Lazy<ActivityStarter>, private val falsingCollector: Lazy<FalsingCollector>, private val userSwitcherViewModel: Lazy<UserSwitcherViewModel>, + private val shadeDialogContextInteractor: Lazy<ShadeDialogContextInteractor>, ) : CoreStartable { private var currentDialog: Dialog? = null @@ -71,12 +71,13 @@ constructor( private fun startHandlingDialogShowRequests() { applicationScope.get().launch { interactor.get().dialogShowRequests.filterNotNull().collect { request -> + val context = shadeDialogContextInteractor.get().context val (dialog, dialogCuj) = when (request) { is ShowDialogRequestModel.ShowAddUserDialog -> Pair( AddUserDialog( - context = context.get(), + context = context, userHandle = request.userHandle, isKeyguardShowing = request.isKeyguardShowing, showEphemeralMessage = request.showEphemeralMessage, @@ -92,7 +93,7 @@ constructor( is ShowDialogRequestModel.ShowUserCreationDialog -> Pair( UserCreatingDialog( - context.get(), + context, request.isGuest, ), null, @@ -100,7 +101,7 @@ constructor( is ShowDialogRequestModel.ShowExitGuestDialog -> Pair( ExitGuestDialog( - context = context.get(), + context = context, guestUserId = request.guestUserId, isGuestEphemeral = request.isGuestEphemeral, targetUserId = request.targetUserId, @@ -117,7 +118,7 @@ constructor( is ShowDialogRequestModel.ShowUserSwitcherDialog -> Pair( UserSwitchDialog( - context = context.get(), + context = context, adapter = userDetailAdapterProvider.get(), uiEventLogger = eventLogger.get(), falsingManager = falsingManager.get(), @@ -132,7 +133,7 @@ constructor( is ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog -> Pair( UserSwitchFullscreenDialog( - context = context.get(), + context = context, falsingCollector = falsingCollector.get(), userSwitcherViewModel = userSwitcherViewModel.get(), ), diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt index f04fb2c3b8d5..1ae56824ca25 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt @@ -24,16 +24,16 @@ import android.widget.ImageButton import androidx.annotation.LayoutRes import androidx.compose.ui.util.fastForEachIndexed import androidx.constraintlayout.motion.widget.MotionLayout -import androidx.constraintlayout.widget.ConstraintSet import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce import com.android.internal.R as internalR import com.android.systemui.res.R -import com.android.systemui.util.children import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope import com.android.systemui.volume.dialog.ringer.ui.util.VolumeDialogRingerDrawerTransitionListener +import com.android.systemui.volume.dialog.ringer.ui.util.updateCloseState +import com.android.systemui.volume.dialog.ringer.ui.util.updateOpenState import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerButtonUiModel import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerButtonViewModel import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerDrawerState @@ -93,6 +93,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { } drawerContainer.setTransitionListener(ringerDrawerTransitionListener) volumeDialogBackgroundView.background = volumeDialogBackgroundView.background.mutate() + viewModel.ringerViewModel .onEach { ringerState -> when (ringerState) { @@ -110,7 +111,10 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { unselectedButtonUiModel, ) ringerDrawerTransitionListener.setProgressChangeEnabled(true) - drawerContainer.closeDrawer(uiModel.currentButtonIndex) + drawerContainer.closeDrawer( + uiModel.currentButtonIndex, + ringerState.orientation, + ) } is RingerDrawerState.Closed -> { @@ -125,8 +129,10 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { unselectedButtonUiModel, onProgressChanged = { progress, isReverse -> // Let's make button progress when switching matches - // motionLayout transition progress. When full radius, - // progress is 0.0. When small radius, progress is 1.0. + // motionLayout transition progress. When full + // radius, + // progress is 0.0. When small radius, progress is + // 1.0. backgroundAnimationProgress = if (isReverse) { 1F - progress @@ -147,7 +153,10 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { true ) } - drawerContainer.closeDrawer(uiModel.currentButtonIndex) + drawerContainer.closeDrawer( + uiModel.currentButtonIndex, + ringerState.orientation, + ) } } } @@ -167,6 +176,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { } else { ringerDrawerTransitionListener.setProgressChangeEnabled(true) } + updateOpenState(drawerContainer, ringerState.orientation) drawerContainer.transitionToState( R.id.volume_dialog_ringer_drawer_open ) @@ -223,23 +233,30 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { // We only need to execute on roundness animation end and volume dialog background // progress update once because these changes should be applied once on volume dialog // background and ringer drawer views. - selectedButton.animateTo( - selectedButtonUiModel, - if (uiModel.currentButtonIndex == count - 1) { - onProgressChanged - } else { - { _, _ -> } - }, - roundnessAnimationEndListener, - ) - unselectedButton.animateTo( - unselectedButtonUiModel, - if (previousIndex == count - 1) { - onProgressChanged - } else { - { _, _ -> } - }, - ) + val selectedCornerRadius = (selectedButton.background as GradientDrawable).cornerRadius + if (selectedCornerRadius.toInt() != selectedButtonUiModel.cornerRadius) { + selectedButton.animateTo( + selectedButtonUiModel, + if (uiModel.currentButtonIndex == count - 1) { + onProgressChanged + } else { + { _, _ -> } + }, + roundnessAnimationEndListener, + ) + } + val unselectedCornerRadius = + (unselectedButton.background as GradientDrawable).cornerRadius + if (unselectedCornerRadius.toInt() != unselectedButtonUiModel.cornerRadius) { + unselectedButton.animateTo( + unselectedButtonUiModel, + if (previousIndex == count - 1) { + onProgressChanged + } else { + { _, _ -> } + }, + ) + } } else { bindButtons(viewModel, uiModel, onAnimationEnd) } @@ -318,107 +335,16 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { inflater.inflate(viewLayoutId, this, true) getChildAt(childCount - 1).id = View.generateViewId() } - cloneConstraintSet(R.id.volume_dialog_ringer_drawer_open) - .adjustOpenConstraintsForDrawer(this) } } } - private fun MotionLayout.closeDrawer(selectedIndex: Int) { + private fun MotionLayout.closeDrawer(selectedIndex: Int, orientation: Int) { setTransition(R.id.close_to_open_transition) - cloneConstraintSet(R.id.volume_dialog_ringer_drawer_close) - .adjustClosedConstraintsForDrawer(selectedIndex, this) + updateCloseState(this, selectedIndex, orientation) transitionToState(R.id.volume_dialog_ringer_drawer_close) } - private fun ConstraintSet.adjustOpenConstraintsForDrawer(motionLayout: MotionLayout) { - motionLayout.children.forEachIndexed { index, button -> - setButtonPositionConstraints(motionLayout, index, button) - setAlpha(button.id, 1.0F) - constrainWidth( - button.id, - motionLayout.context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_ringer_drawer_button_size - ), - ) - constrainHeight( - button.id, - motionLayout.context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_ringer_drawer_button_size - ), - ) - if (index != motionLayout.childCount - 1) { - setMargin( - button.id, - ConstraintSet.BOTTOM, - motionLayout.context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_components_spacing - ), - ) - } - } - motionLayout.updateState(R.id.volume_dialog_ringer_drawer_open, this) - } - - private fun ConstraintSet.adjustClosedConstraintsForDrawer( - selectedIndex: Int, - motionLayout: MotionLayout, - ) { - motionLayout.children.forEachIndexed { index, button -> - setButtonPositionConstraints(motionLayout, index, button) - constrainWidth( - button.id, - motionLayout.context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_ringer_drawer_button_size - ), - ) - if (selectedIndex != motionLayout.childCount - index - 1) { - setAlpha(button.id, 0.0F) - constrainHeight(button.id, 0) - setMargin(button.id, ConstraintSet.BOTTOM, 0) - } else { - setAlpha(button.id, 1.0F) - constrainHeight( - button.id, - motionLayout.context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_ringer_drawer_button_size - ), - ) - } - } - motionLayout.updateState(R.id.volume_dialog_ringer_drawer_close, this) - } - - private fun ConstraintSet.setButtonPositionConstraints( - motionLayout: MotionLayout, - index: Int, - button: View, - ) { - if (motionLayout.getChildAt(index - 1) == null) { - connect(button.id, ConstraintSet.TOP, motionLayout.id, ConstraintSet.TOP) - } else { - connect( - button.id, - ConstraintSet.TOP, - motionLayout.getChildAt(index - 1).id, - ConstraintSet.BOTTOM, - ) - } - - if (motionLayout.getChildAt(index + 1) == null) { - connect(button.id, ConstraintSet.BOTTOM, motionLayout.id, ConstraintSet.BOTTOM) - } else { - connect( - button.id, - ConstraintSet.BOTTOM, - motionLayout.getChildAt(index + 1).id, - ConstraintSet.TOP, - ) - } - connect(button.id, ConstraintSet.START, motionLayout.id, ConstraintSet.START) - connect(button.id, ConstraintSet.END, motionLayout.id, ConstraintSet.END) - } - private suspend fun ImageButton.animateTo( ringerButtonUiModel: RingerButtonUiModel, onProgressChanged: (Float, Boolean) -> Unit = { _, _ -> }, diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt new file mode 100644 index 000000000000..25ba1bd3a1d8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt @@ -0,0 +1,208 @@ +/* + * 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.volume.dialog.ringer.ui.util + +import android.content.res.Configuration.ORIENTATION_LANDSCAPE +import android.content.res.Configuration.ORIENTATION_PORTRAIT +import android.view.View +import androidx.constraintlayout.motion.widget.MotionLayout +import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.res.R +import com.android.systemui.util.children + +fun updateOpenState(ringerDrawer: MotionLayout, orientation: Int) { + val openSet = ringerDrawer.cloneConstraintSet(R.id.volume_dialog_ringer_drawer_open) + openSet.adjustOpenConstraintsForDrawer(ringerDrawer, orientation) + ringerDrawer.updateState(R.id.volume_dialog_ringer_drawer_open, openSet) +} + +fun updateCloseState(ringerDrawer: MotionLayout, selectedIndex: Int, orientation: Int) { + val closeSet = ringerDrawer.cloneConstraintSet(R.id.volume_dialog_ringer_drawer_close) + closeSet.adjustClosedConstraintsForDrawer(ringerDrawer, selectedIndex, orientation) + ringerDrawer.updateState(R.id.volume_dialog_ringer_drawer_close, closeSet) +} + +private fun ConstraintSet.setButtonPositionPortraitConstraints( + motionLayout: MotionLayout, + index: Int, + button: View, +) { + if (motionLayout.getChildAt(index - 1) == null) { + connect(button.id, ConstraintSet.TOP, motionLayout.id, ConstraintSet.TOP) + } else { + connect( + button.id, + ConstraintSet.TOP, + motionLayout.getChildAt(index - 1).id, + ConstraintSet.BOTTOM, + ) + } + + if (motionLayout.getChildAt(index + 1) == null) { + connect(button.id, ConstraintSet.BOTTOM, motionLayout.id, ConstraintSet.BOTTOM) + } else { + connect( + button.id, + ConstraintSet.BOTTOM, + motionLayout.getChildAt(index + 1).id, + ConstraintSet.TOP, + ) + } + connect(button.id, ConstraintSet.START, motionLayout.id, ConstraintSet.START) + connect(button.id, ConstraintSet.END, motionLayout.id, ConstraintSet.END) + clear(button.id, ConstraintSet.LEFT) + clear(button.id, ConstraintSet.RIGHT) +} + +private fun ConstraintSet.setButtonPositionLandscapeConstraints( + motionLayout: MotionLayout, + index: Int, + button: View, +) { + if (motionLayout.getChildAt(index - 1) == null) { + connect(button.id, ConstraintSet.LEFT, motionLayout.id, ConstraintSet.LEFT) + } else { + connect( + button.id, + ConstraintSet.LEFT, + motionLayout.getChildAt(index - 1).id, + ConstraintSet.RIGHT, + ) + } + if (motionLayout.getChildAt(index + 1) == null) { + connect(button.id, ConstraintSet.RIGHT, motionLayout.id, ConstraintSet.RIGHT) + } else { + connect( + button.id, + ConstraintSet.RIGHT, + motionLayout.getChildAt(index + 1).id, + ConstraintSet.LEFT, + ) + } + connect(button.id, ConstraintSet.TOP, motionLayout.id, ConstraintSet.TOP) + connect(button.id, ConstraintSet.BOTTOM, motionLayout.id, ConstraintSet.BOTTOM) + clear(button.id, ConstraintSet.START) + clear(button.id, ConstraintSet.END) +} + +private fun ConstraintSet.adjustOpenConstraintsForDrawer( + motionLayout: MotionLayout, + lastOrientation: Int, +) { + motionLayout.children.forEachIndexed { index, button -> + setAlpha(button.id, 1.0F) + constrainWidth( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + constrainHeight( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + when (lastOrientation) { + ORIENTATION_LANDSCAPE -> { + setButtonPositionLandscapeConstraints(motionLayout, index, button) + if (index != motionLayout.childCount - 1) { + setMargin( + button.id, + ConstraintSet.RIGHT, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_components_spacing + ), + ) + } else { + setMargin(button.id, ConstraintSet.RIGHT, 0) + } + setMargin(button.id, ConstraintSet.BOTTOM, 0) + } + ORIENTATION_PORTRAIT -> { + setButtonPositionPortraitConstraints(motionLayout, index, button) + if (index != motionLayout.childCount - 1) { + setMargin( + button.id, + ConstraintSet.BOTTOM, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_components_spacing + ), + ) + } else { + setMargin(button.id, ConstraintSet.BOTTOM, 0) + } + setMargin(button.id, ConstraintSet.RIGHT, 0) + } + } + } +} + +private fun ConstraintSet.adjustClosedConstraintsForDrawer( + motionLayout: MotionLayout, + selectedIndex: Int, + lastOrientation: Int, +) { + motionLayout.children.forEachIndexed { index, button -> + setMargin(button.id, ConstraintSet.RIGHT, 0) + setMargin(button.id, ConstraintSet.BOTTOM, 0) + when (lastOrientation) { + ORIENTATION_LANDSCAPE -> { + setButtonPositionLandscapeConstraints(motionLayout, index, button) + if (selectedIndex != motionLayout.childCount - index - 1) { + setAlpha(button.id, 0.0F) + constrainWidth(button.id, 0) + } else { + setAlpha(button.id, 1.0F) + constrainWidth( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + } + constrainHeight( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + } + ORIENTATION_PORTRAIT -> { + setButtonPositionPortraitConstraints(motionLayout, index, button) + if (selectedIndex != motionLayout.childCount - index - 1) { + setAlpha(button.id, 0.0F) + constrainHeight(button.id, 0) + } else { + setAlpha(button.id, 1.0F) + constrainHeight( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + } + constrainWidth( + button.id, + motionLayout.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_drawer_button_size + ), + ) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModelState.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModelState.kt index 78b00afa9510..50898b670938 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModelState.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerViewModelState.kt @@ -19,7 +19,8 @@ package com.android.systemui.volume.dialog.ringer.ui.viewmodel /** Models ringer view model state. */ sealed class RingerViewModelState { - data class Available(val uiModel: RingerViewModel) : RingerViewModelState() + data class Available(val uiModel: RingerViewModel, val orientation: Int) : + RingerViewModelState() data object Unavailable : RingerViewModelState() } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt index 627d75ee108d..eec64d9a2f86 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt @@ -33,6 +33,8 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.res.R import com.android.systemui.statusbar.VibratorHelper +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.onConfigChanged import com.android.systemui.volume.Events import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope @@ -48,6 +50,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -65,19 +68,29 @@ constructor( private val vibrator: VibratorHelper, private val volumeDialogLogger: VolumeDialogLogger, private val visibilityInteractor: VolumeDialogVisibilityInteractor, + configurationController: ConfigurationController, ) { private val drawerState = MutableStateFlow<RingerDrawerState>(RingerDrawerState.Initial) + private val orientation: StateFlow<Int> = + configurationController.onConfigChanged + .map { it.orientation } + .stateIn( + coroutineScope, + SharingStarted.Eagerly, + applicationContext.resources.configuration.orientation, + ) val ringerViewModel: StateFlow<RingerViewModelState> = combine( soundPolicyInteractor.isZenMuted(AudioStream(STREAM_RING)), ringerInteractor.ringerModel, drawerState, - ) { isZenMuted, ringerModel, state -> + orientation, + ) { isZenMuted, ringerModel, state, orientation -> level = ringerModel.level levelMax = ringerModel.levelMax - ringerModel.toViewModel(state, isZenMuted) + ringerModel.toViewModel(state, isZenMuted, orientation) } .flowOn(backgroundDispatcher) .stateIn(coroutineScope, SharingStarted.Eagerly, RingerViewModelState.Unavailable) @@ -133,6 +146,7 @@ constructor( private fun VolumeDialogRingerModel.toViewModel( drawerState: RingerDrawerState, isZenMuted: Boolean, + orientation: Int, ): RingerViewModelState { val currentIndex = availableModes.indexOf(currentRingerMode) if (currentIndex == -1) { @@ -149,7 +163,8 @@ constructor( currentButtonIndex = currentIndex, selectedButton = it, drawerState = drawerState, - ) + ), + orientation, ) } ?: RingerViewModelState.Unavailable } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt index 2e1f82d56fc4..70e342f3eefb 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt @@ -17,45 +17,28 @@ package com.android.systemui.volume.dialog.settings.ui.binder import android.view.View -import com.android.systemui.lifecycle.WindowLifecycleState -import com.android.systemui.lifecycle.repeatWhenAttached -import com.android.systemui.lifecycle.setSnapshotBinding -import com.android.systemui.lifecycle.viewModel +import android.widget.ImageButton import com.android.systemui.res.R import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel import javax.inject.Inject -import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @VolumeDialogScope class VolumeDialogSettingsButtonViewBinder @Inject -constructor(private val viewModelFactory: VolumeDialogSettingsButtonViewModel.Factory) { +constructor(private val viewModel: VolumeDialogSettingsButtonViewModel) { - fun bind(view: View) { - with(view) { - val button = requireViewById<View>(R.id.volume_dialog_settings) - repeatWhenAttached { - viewModel( - traceName = "VolumeDialogViewBinder", - minWindowLifecycleState = WindowLifecycleState.ATTACHED, - factory = { viewModelFactory.create() }, - ) { viewModel -> - setSnapshotBinding { - viewModel.isVisible - .onEach { isVisible -> - visibility = if (isVisible) View.VISIBLE else View.GONE - } - .launchIn(this) + fun CoroutineScope.bind(view: View) { + val button = view.requireViewById<ImageButton>(R.id.volume_dialog_settings) + viewModel.isVisible + .onEach { isVisible -> button.visibility = if (isVisible) View.VISIBLE else View.GONE } + .launchIn(this) - button.setOnClickListener { viewModel.onButtonClicked() } - } + viewModel.icon.onEach { button.setImageDrawable(it) }.launchIn(this) - awaitCancellation() - } - } - } + button.setOnClickListener { viewModel.onButtonClicked() } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt index 015d773b2c02..03442dbcde66 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt @@ -14,27 +14,206 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.volume.dialog.settings.ui.viewmodel -import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.ColorFilter +import android.graphics.drawable.Drawable +import android.media.session.PlaybackState +import androidx.annotation.ColorInt +import com.airbnb.lottie.LottieComposition +import com.airbnb.lottie.LottieCompositionFactory +import com.airbnb.lottie.LottieDrawable +import com.airbnb.lottie.LottieProperty +import com.airbnb.lottie.SimpleColorFilter +import com.airbnb.lottie.model.KeyPath +import com.airbnb.lottie.value.LottieValueCallback +import com.android.internal.R as internalR +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.UiBackground +import com.android.systemui.lottie.await +import com.android.systemui.res.R +import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog import com.android.systemui.volume.dialog.settings.domain.VolumeDialogSettingsButtonInteractor -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor +import com.android.systemui.volume.panel.shared.model.filterData +import javax.inject.Inject +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.resume +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.runningFold +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.transform +import kotlinx.coroutines.suspendCancellableCoroutine class VolumeDialogSettingsButtonViewModel -@AssistedInject -constructor(private val interactor: VolumeDialogSettingsButtonInteractor) { +@Inject +constructor( + @Application private val context: Context, + @UiBackground private val uiBgCoroutineContext: CoroutineContext, + @VolumeDialog private val coroutineScope: CoroutineScope, + mediaOutputInteractor: MediaOutputInteractor, + private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, + private val interactor: VolumeDialogSettingsButtonInteractor, +) { + + @SuppressLint("UseCompatLoadingForDrawables") + private val drawables: Flow<Drawables> = + flow { + val color = context.getColor(internalR.color.materialColorPrimary) + emit( + Drawables( + start = + LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_in) + .await() + .toDrawable { setColor(color) }, + playing = + LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_playing) + .await() + .toDrawable { + repeatCount = LottieDrawable.INFINITE + repeatMode = LottieDrawable.RESTART + setColor(color) + }, + stop = + LottieCompositionFactory.fromRawRes(context, R.raw.audio_bars_out) + .await() + .toDrawable { setColor(color) }, + idle = context.getDrawable(R.drawable.audio_bars_idle)!!, + ) + ) + } + .buffer() + .flowOn(uiBgCoroutineContext) + .stateIn(coroutineScope, SharingStarted.Eagerly, null) + .filterNotNull() val isVisible = interactor.isVisible + val icon: Flow<Drawable> = + mediaOutputInteractor.defaultActiveMediaSession + .filterData() + .flatMapLatest { session -> + if (session == null) { + flowOf(null) + } else { + mediaDeviceSessionInteractor.playbackState(session) + } + } + .runningFold(null) { playbackStates: PlaybackStates?, playbackState: PlaybackState? -> + val isCurrentActive = playbackState?.isActive ?: false + if (playbackStates != null && isCurrentActive == playbackState?.isActive) { + return@runningFold playbackStates + } + playbackStates?.copy( + isPreviousActive = playbackStates.isCurrentActive, + isCurrentActive = isCurrentActive, + ) ?: PlaybackStates(isPreviousActive = null, isCurrentActive = isCurrentActive) + } + .filterNotNull() + // only apply the most recent state if we wait for the animation. + .buffer(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + // distinct again because the changed state might've been dropped by the buffer + .distinctUntilChangedBy { it.isCurrentActive } + .transform { emitDrawables(it) } + .runningFold(null) { previous: Drawable?, current: Drawable -> + // wait for the previous animation to finish before starting the new one + // this also waits for the current loop of the playing animation to finish + (previous as? LottieDrawable)?.awaitFinish() + (current as? LottieDrawable)?.start() + current + } + .filterNotNull() + + private suspend fun FlowCollector<Drawable>.emitDrawables(playbackStates: PlaybackStates) { + val animations = drawables.first() + val stateChanged = + playbackStates.isPreviousActive != null && + playbackStates.isPreviousActive != playbackStates.isCurrentActive + if (playbackStates.isCurrentActive) { + if (stateChanged) { + emit(animations.start) + } + emit(animations.playing) + } else { + if (stateChanged) { + emit(animations.stop) + } + emit(animations.idle) + } + } fun onButtonClicked() { interactor.onButtonClicked() } - @VolumeDialogScope - @AssistedFactory - interface Factory { + private data class PlaybackStates(val isPreviousActive: Boolean?, val isCurrentActive: Boolean) + + private data class Drawables( + val start: LottieDrawable, + val playing: LottieDrawable, + val stop: LottieDrawable, + val idle: Drawable, + ) +} + +private fun LottieComposition.toDrawable(setup: LottieDrawable.() -> Unit = {}): LottieDrawable = + LottieDrawable().also { drawable -> + drawable.composition = this + drawable.setup() + } - fun create(): VolumeDialogSettingsButtonViewModel +/** Suspends until current loop of the repeating animation is finished */ +private suspend fun LottieDrawable.awaitFinish() = suspendCancellableCoroutine { continuation -> + if (!isRunning) { + continuation.resume(Unit) + return@suspendCancellableCoroutine } + val listener = + object : AnimatorListenerAdapter() { + override fun onAnimationRepeat(animation: Animator) { + continuation.resume(Unit) + removeAnimatorListener(this) + } + + override fun onAnimationEnd(animation: Animator) { + continuation.resume(Unit) + removeAnimatorListener(this) + } + + override fun onAnimationCancel(animation: Animator) { + continuation.resume(Unit) + removeAnimatorListener(this) + } + } + addAnimatorListener(listener) + continuation.invokeOnCancellation { removeAnimatorListener(listener) } +} + +/** + * Overrides colors of the [LottieDrawable] to a specified [color] + * + * @see com.airbnb.lottie.LottieAnimationView + */ +private fun LottieDrawable.setColor(@ColorInt color: Int) { + val callback = LottieValueCallback<ColorFilter>(SimpleColorFilter(color)) + addValueCallback(KeyPath("**"), LottieProperty.COLOR_FILTER, callback) } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt index c0c525bcb37d..88af210b6a36 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.dialog.sliders.dagger import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType +import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogOverscrollViewBinder import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderHapticsViewBinder import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderTouchesViewBinder import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder @@ -37,6 +38,8 @@ interface VolumeDialogSliderComponent { fun sliderHapticsViewBinder(): VolumeDialogSliderHapticsViewBinder + fun overscrollViewBinder(): VolumeDialogOverscrollViewBinder + @Subcomponent.Factory interface Factory { diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt index adc2383c3a46..82885d65c513 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/data/repository/VolumeDialogSliderTouchEventsRepository.kt @@ -16,7 +16,6 @@ package com.android.systemui.volume.dialog.sliders.data.repository -import android.annotation.SuppressLint import android.view.MotionEvent import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import javax.inject.Inject @@ -27,7 +26,6 @@ import kotlinx.coroutines.flow.filterNotNull @VolumeDialogSliderScope class VolumeDialogSliderTouchEventsRepository @Inject constructor() { - @SuppressLint("SharedFlowCreation") private val mutableSliderTouchEvents: MutableStateFlow<MotionEvent?> = MutableStateFlow(null) val sliderTouchEvent: Flow<MotionEvent> = mutableSliderTouchEvents.filterNotNull() diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt index 2967fe8ca906..04dc80c45a18 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractor.kt @@ -17,14 +17,18 @@ package com.android.systemui.volume.dialog.sliders.domain.interactor import com.android.systemui.plugins.VolumeDialogController +import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.stateIn /** Operates a state of particular slider of the Volume Dialog. */ @VolumeDialogSliderScope @@ -32,6 +36,7 @@ class VolumeDialogSliderInteractor @Inject constructor( private val sliderType: VolumeDialogSliderType, + @VolumeDialog private val coroutineScope: CoroutineScope, volumeDialogStateInteractor: VolumeDialogStateInteractor, private val volumeDialogController: VolumeDialogController, ) { @@ -47,7 +52,8 @@ constructor( } } } - .distinctUntilChanged() + .stateIn(coroutineScope, SharingStarted.Eagerly, null) + .filterNotNull() fun setStreamVolume(userLevel: Int) { with(volumeDialogController) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt index c904ac5e3ae1..690f9ef9e6d8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt @@ -63,7 +63,7 @@ constructor( LinkedHashSet(sliderTypes) } .runningReduce { sliderTypes, newSliderTypes -> - newSliderTypes.apply { addAll(sliderTypes) } + sliderTypes.apply { addAll(newSliderTypes) } } .map { sliderTypes -> VolumeDialogSlidersModel( diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt new file mode 100644 index 000000000000..8109b50aa34a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt @@ -0,0 +1,79 @@ +/* + * 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.volume.dialog.sliders.ui + +import android.view.View +import androidx.dynamicanimation.animation.FloatValueHolder +import androidx.dynamicanimation.animation.SpringAnimation +import androidx.dynamicanimation.animation.SpringForce +import com.android.systemui.res.R +import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope +import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel +import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel.OverscrollEventModel +import com.google.android.material.slider.Slider +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@VolumeDialogSliderScope +class VolumeDialogOverscrollViewBinder +@Inject +constructor(private val viewModel: VolumeDialogOverscrollViewModel) { + + /** + * [viewsToAnimate] is an array of [View] to be affected by the overscroll animation. [view] is + * NOT animated by default. + */ + fun CoroutineScope.bind(view: View, viewsToAnimate: Array<View>) { + val animationValueHolder = FloatValueHolder(0f) + val animation: SpringAnimation = + SpringAnimation(animationValueHolder) + .setSpring( + SpringForce(0f).apply { + stiffness = 800f + dampingRatio = 0.6f + } + ) + .addUpdateListener { _, value, _ -> viewsToAnimate.setTranslationY(value) } + + view.requireViewById<Slider>(R.id.volume_dialog_slider).addOnChangeListener { s, value, _ -> + viewModel.setSlider(value = value, min = s.valueFrom, max = s.valueTo) + } + + viewModel.overscrollEvent + .onEach { event -> + when (event) { + is OverscrollEventModel.Animate -> { + animation.animateToFinalPosition(event.targetOffsetPx) + } + is OverscrollEventModel.Move -> { + animation.cancel() + viewsToAnimate.setTranslationY(event.touchOffsetPx) + animationValueHolder.value = event.touchOffsetPx + } + } + } + .launchIn(this) + } +} + +private fun Array<View>.setTranslationY(translation: Float) { + for (viewToAnimate in this) { + viewToAnimate.translationY = translation + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt index f30524638150..a7ffcd747a6b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt @@ -26,7 +26,7 @@ import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderStateModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory -import com.android.systemui.volume.dialog.ui.utils.awaitAnimation +import com.android.systemui.volume.dialog.ui.utils.suspendAnimate import com.google.android.material.slider.LabelFormatter import com.google.android.material.slider.Slider import javax.inject.Inject @@ -55,22 +55,21 @@ constructor( viewModel.setStreamVolume(value.roundToInt(), fromUser) } - viewModel.state.onEach { it.bindToSlider(sliderView) }.launchIn(this) + viewModel.state.onEach { sliderView.setModel(it) }.launchIn(this) } @SuppressLint("UseCompatLoadingForDrawables") - private suspend fun VolumeDialogSliderStateModel.bindToSlider(slider: Slider) { - with(slider) { - valueFrom = minValue - valueTo = maxValue - // coerce the current value to the new value range before animating it - value = value.coerceIn(valueFrom, valueTo) - setValueAnimated( - value, - jankListenerFactory.update(this, PROGRESS_CHANGE_ANIMATION_DURATION_MS), - ) - trackIconActiveEnd = context.getDrawable(iconRes) - } + private suspend fun Slider.setModel(model: VolumeDialogSliderStateModel) { + valueFrom = model.minValue + valueTo = model.maxValue + // coerce the current value to the new value range before animating it. This prevents + // animating from the value that is outside of current [valueFrom, valueTo]. + value = value.coerceIn(valueFrom, valueTo) + setValueAnimated( + model.value, + jankListenerFactory.update(this, PROGRESS_CHANGE_ANIMATION_DURATION_MS), + ) + trackIconActiveEnd = context.getDrawable(model.iconRes) } } @@ -84,5 +83,5 @@ private suspend fun Slider.setValueAnimated( interpolator = DecelerateInterpolator() addListener(jankListener) } - .awaitAnimation<Float> { value = it } + .suspendAnimate<Float> { value = it } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt index c9b525930ed3..f066b56e7de0 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt @@ -40,9 +40,17 @@ constructor(private val viewModel: VolumeDialogSlidersViewModel) { view.requireViewById(R.id.volume_dialog_floating_sliders_container) val mainSliderContainer: View = view.requireViewById(R.id.volume_dialog_main_slider_container) + val background: View = view.requireViewById(R.id.volume_dialog_background) + val settingsButton: View = view.requireViewById(R.id.volume_dialog_settings) + val ringerDrawer: View = view.requireViewById(R.id.volume_ringer_drawer) + viewModel.sliders .onEach { uiModel -> - bindSlider(uiModel.sliderComponent, mainSliderContainer) + bindSlider( + uiModel.sliderComponent, + mainSliderContainer, + arrayOf(mainSliderContainer, background, settingsButton, ringerDrawer), + ) val floatingSliderViewBinders = uiModel.floatingSliderComponent floatingSlidersContainer.ensureChildCount( @@ -50,7 +58,8 @@ constructor(private val viewModel: VolumeDialogSlidersViewModel) { count = floatingSliderViewBinders.size, ) floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent -> - bindSlider(sliderComponent, floatingSlidersContainer.getChildAt(index)) + val sliderContainer = floatingSlidersContainer.getChildAt(index) + bindSlider(sliderComponent, sliderContainer, arrayOf(sliderContainer)) } } .launchIn(this) @@ -59,10 +68,12 @@ constructor(private val viewModel: VolumeDialogSlidersViewModel) { private fun CoroutineScope.bindSlider( component: VolumeDialogSliderComponent, sliderContainer: View, + viewsToAnimate: Array<View>, ) { with(component.sliderViewBinder()) { bind(sliderContainer) } with(component.sliderTouchesViewBinder()) { bind(sliderContainer) } with(component.sliderHapticsViewBinder()) { bind(sliderContainer) } + with(component.overscrollViewBinder()) { bind(sliderContainer, viewsToAnimate) } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogOverscrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogOverscrollViewModel.kt new file mode 100644 index 000000000000..0d41860d9f57 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogOverscrollViewModel.kt @@ -0,0 +1,152 @@ +/* + * 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.volume.dialog.sliders.ui.viewmodel + +import android.content.Context +import android.view.MotionEvent +import android.view.animation.PathInterpolator +import com.android.systemui.res.R +import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope +import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInputEventsInteractor +import com.android.systemui.volume.dialog.sliders.shared.model.SliderInputEvent +import javax.inject.Inject +import kotlin.math.abs +import kotlin.math.sign +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.transform + +@VolumeDialogSliderScope +@OptIn(ExperimentalCoroutinesApi::class) +class VolumeDialogOverscrollViewModel +@Inject +constructor( + context: Context, + private val inputEventsInteractor: VolumeDialogSliderInputEventsInteractor, +) { + + /** + * This is the ratio between the pointer distance and the dialog offset. The pointer has to + * travel this distance for a single point of an offset. + * + * When greater than 1 this makes the dialog to follow the touch behind. + */ + private val offsetToTranslationRatio: Float = 3f + private val maxDeviation: Float = + context.resources + .getDimensionPixelSize(R.dimen.volume_dialog_slider_max_deviation) + .toFloat() + private val offsetInterpolator = PathInterpolator(0.15f, 0.00f, 0.20f, 1.00f) + + private val sliderValue = MutableStateFlow<Slider?>(null) + + val overscrollEvent: Flow<OverscrollEventModel> = + sliderValue + .filterNotNull() + .map { slider -> + when (slider.value) { + slider.min -> 1f + slider.max -> -1f + else -> 0f + } + } + .distinctUntilChanged() + .flatMapLatest { direction -> + if (direction == 0f) { + flowOf(OverscrollEventModel.Animate(0f)) + } else { + overscrollEvents(direction) + } + } + + fun setSlider(value: Float, min: Float, max: Float) { + sliderValue.value = Slider(value = value, min = min, max = max) + } + + /** + * Returns a flow that for each another [MotionEvent] it receives maps into a path from the + * first event. + * + * Emits [OverscrollEventModel.Move] that follows the [SliderInputEvent.Touch] from the pointer + * down position. Emits [OverscrollEventModel.Animate] when the gesture is terminated to create + * a spring-back effect. + */ + private fun overscrollEvents(direction: Float): Flow<OverscrollEventModel> { + var startPosition: Float? = null + return inputEventsInteractor.event + .mapNotNull { (it as? SliderInputEvent.Touch)?.event } + .transform { touchEvent -> + // Skip events from inside the slider bounds for the case when the user adjusts + // slider + // towards max when the slider is already on max value. + if (touchEvent.isFinalEvent()) { + startPosition = null + emit(OverscrollEventModel.Animate(0f)) + return@transform + } + val currentStartPosition = startPosition + val newPosition: Float = touchEvent.rawY + if (currentStartPosition == null) { + startPosition = newPosition + } else { + val offset = (newPosition - currentStartPosition) / offsetToTranslationRatio + val interpolatedOffset = + if (areOfTheSameSign(direction, offset)) { + sign(offset) * + (maxDeviation * + offsetInterpolator.getInterpolation( + (abs(offset)) / maxDeviation + )) + } else { + 0f + } + emit(OverscrollEventModel.Move(interpolatedOffset)) + } + } + } + + /** @return true when the [MotionEvent] indicates the end of the gesture. */ + private fun MotionEvent.isFinalEvent(): Boolean { + return actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL + } + + /** Models overscroll event */ + sealed interface OverscrollEventModel { + + /** Notifies the consumed to move by the [touchOffsetPx]. */ + data class Move(val touchOffsetPx: Float) : OverscrollEventModel + + /** Notifies the consume to animate to the [targetOffsetPx]. */ + data class Animate(val targetOffsetPx: Float) : OverscrollEventModel + } + + private data class Slider(val value: Float, val min: Float, val max: Float) +} + +private fun areOfTheSameSign(lhs: Float, rhs: Float): Boolean = + when { + lhs < 0 -> rhs < 0 + lhs > 0 -> rhs > 0 + else -> rhs == 0f + } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt index 10cf615ce0ce..5f124806dac7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/utils/SuspendAnimators.kt @@ -22,6 +22,7 @@ import android.animation.ValueAnimator import android.view.ViewPropertyAnimator import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.SpringAnimation +import com.airbnb.lottie.LottieDrawable import kotlin.coroutines.resume import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine @@ -66,7 +67,7 @@ suspend fun ViewPropertyAnimator.suspendAnimate( * is cancelled. */ @Suppress("UNCHECKED_CAST") -suspend fun <T> ValueAnimator.awaitAnimation(onValueChanged: (T) -> Unit) { +suspend fun <T> ValueAnimator.suspendAnimate(onValueChanged: (T) -> Unit) { suspendCancellableCoroutine { continuation -> addListener( object : AnimatorListenerAdapter() { @@ -103,6 +104,29 @@ suspend fun SpringAnimation.suspendAnimate( } } +/** + * Starts the animation and suspends until it's finished. Cancels the animation if the running + * coroutine is cancelled. + */ +suspend fun LottieDrawable.suspendAnimate() = suspendCancellableCoroutine { continuation -> + val listener = + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + continuation.resumeIfCan(Unit) + } + + override fun onAnimationCancel(animation: Animator) { + continuation.resumeIfCan(Unit) + } + } + addAnimatorListener(listener) + start() + continuation.invokeOnCancellation { + removeAnimatorListener(listener) + stop() + } +} + private fun <T> CancellableContinuation<T>.resumeIfCan(value: T) { if (!isCancelled && !isCompleted) { resume(value) diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt index 6e1ebc820b08..12e624cae4d4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaDeviceSessionInteractor.kt @@ -19,10 +19,10 @@ package com.android.systemui.volume.panel.component.mediaoutput.domain.interacto import android.media.session.MediaController import android.media.session.PlaybackState import com.android.settingslib.volume.data.repository.MediaControllerRepository +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaControllerChangeModel import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession -import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -38,7 +38,7 @@ import kotlinx.coroutines.withContext /** Allows to observe and change [MediaDeviceSession] state. */ @OptIn(ExperimentalCoroutinesApi::class) -@VolumePanelScope +@SysUISingleton class MediaDeviceSessionInteractor @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt index b3848a6d7817..2973e11c365d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt @@ -24,12 +24,13 @@ import androidx.annotation.WorkerThread import com.android.settingslib.media.MediaDevice import com.android.settingslib.volume.data.repository.LocalMediaRepository import com.android.settingslib.volume.data.repository.MediaControllerRepository +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.concurrency.Execution import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory import com.android.systemui.volume.panel.component.mediaoutput.domain.model.MediaDeviceSessions import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession -import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import com.android.systemui.volume.panel.shared.model.Result import com.android.systemui.volume.panel.shared.model.filterData import com.android.systemui.volume.panel.shared.model.wrapInResult @@ -54,13 +55,13 @@ import kotlinx.coroutines.withContext /** Provides observable models about the current media session state. */ @OptIn(ExperimentalCoroutinesApi::class) -@VolumePanelScope +@SysUISingleton class MediaOutputInteractor @Inject constructor( private val localMediaRepositoryFactory: LocalMediaRepositoryFactory, private val packageManager: PackageManager, - @VolumePanelScope private val coroutineScope: CoroutineScope, + @Application private val coroutineScope: CoroutineScope, @Background private val backgroundCoroutineContext: CoroutineContext, mediaControllerRepository: MediaControllerRepository, private val mediaControllerInteractor: MediaControllerInteractor, @@ -77,7 +78,7 @@ constructor( .onStart { emit(activeSessions) } } .map { getMediaControllers(it) } - .stateIn(coroutineScope, SharingStarted.Eagerly, MediaControllers(null, null)) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), MediaControllers(null, null)) /** [MediaDeviceSessions] that contains currently active sessions. */ val activeMediaDeviceSessions: Flow<MediaDeviceSessions> = @@ -89,7 +90,11 @@ constructor( ) } .flowOn(backgroundCoroutineContext) - .stateIn(coroutineScope, SharingStarted.Eagerly, MediaDeviceSessions(null, null)) + .stateIn( + coroutineScope, + SharingStarted.WhileSubscribed(), + MediaDeviceSessions(null, null), + ) /** Returns the default [MediaDeviceSession] from [activeMediaDeviceSessions] */ val defaultActiveMediaSession: StateFlow<Result<MediaDeviceSession?>> = @@ -104,7 +109,7 @@ constructor( } .wrapInResult() .flowOn(backgroundCoroutineContext) - .stateIn(coroutineScope, SharingStarted.Eagerly, Result.Loading()) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), Result.Loading()) private val localMediaRepository: Flow<LocalMediaRepository> = defaultActiveMediaSession diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index a41725f754df..4abbbacd800b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -25,7 +25,6 @@ import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE -import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.flags.Flags @@ -299,20 +298,6 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun keyguardCallback_visibilityChanged_clockDozeCalled() = - runBlocking(IMMEDIATE) { - val captor = argumentCaptor<KeyguardUpdateMonitorCallback>() - verify(keyguardUpdateMonitor).registerCallback(capture(captor)) - - captor.value.onKeyguardVisibilityChanged(true) - verify(animations, never()).doze(0f) - - captor.value.onKeyguardVisibilityChanged(false) - verify(animations, times(2)).doze(0f) - } - - @Test fun keyguardCallback_timeFormat_clockNotified() = runBlocking(IMMEDIATE) { val captor = argumentCaptor<KeyguardUpdateMonitorCallback>() @@ -344,19 +329,6 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun keyguardCallback_verifyKeyguardChanged() = - runBlocking(IMMEDIATE) { - val job = underTest.listenForDozeAmount(this) - repository.setDozeAmount(0.4f) - - yield() - - verify(animations, times(2)).doze(0.4f) - - job.cancel() - } - - @Test fun listenForDozeAmountTransition_updatesClockDozeAmount() = runBlocking(IMMEDIATE) { val transitionStep = MutableStateFlow(TransitionStep()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt index 4aaa82e4a16d..37eb148a5ea7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt @@ -14,6 +14,8 @@ import android.testing.TestableLooper.RunWithLooper import android.view.IRemoteAnimationFinishedCallback import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget +import android.view.RemoteAnimationTarget.MODE_CLOSING +import android.view.RemoteAnimationTarget.MODE_OPENING import android.view.SurfaceControl import android.view.ViewGroup import android.view.WindowManager.TRANSIT_NONE @@ -36,10 +38,6 @@ import junit.framework.Assert.assertTrue import junit.framework.AssertionFailedError import kotlin.concurrent.thread import kotlin.test.assertEquals -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeout import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before @@ -49,6 +47,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mock +import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` @@ -215,22 +214,12 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun registersLongLivedTransition() { - activityTransitionAnimator.register( - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = - ActivityTransitionAnimator.TransitionCookie("test_cookie_1") - override val component = ComponentName("com.test.package", "Test1") - } - ) + var factory = controllerFactory() + activityTransitionAnimator.register(factory.cookie, factory) assertEquals(2, testShellTransitions.remotes.size) - activityTransitionAnimator.register( - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = - ActivityTransitionAnimator.TransitionCookie("test_cookie_2") - override val component = ComponentName("com.test.package", "Test2") - } - ) + factory = controllerFactory() + activityTransitionAnimator.register(factory.cookie, factory) assertEquals(4, testShellTransitions.remotes.size) } @@ -241,20 +230,12 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun registersLongLivedTransitionOverridingPreviousRegistration() { val cookie = ActivityTransitionAnimator.TransitionCookie("test_cookie") - activityTransitionAnimator.register( - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = cookie - override val component = ComponentName("com.test.package", "Test1") - } - ) + var factory = controllerFactory(cookie) + activityTransitionAnimator.register(cookie, factory) val transitions = testShellTransitions.remotes.values.toList() - activityTransitionAnimator.register( - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = cookie - override val component = ComponentName("com.test.package", "Test2") - } - ) + factory = controllerFactory(cookie) + activityTransitionAnimator.register(cookie, factory) assertEquals(2, testShellTransitions.remotes.size) for (transition in transitions) { assertThat(testShellTransitions.remotes.values).doesNotContain(transition) @@ -264,38 +245,19 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { - val controller = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = - ActivityTransitionAnimator.TransitionCookie("test_cookie") - override val component = ComponentName("com.test.package", "Test") - } + val factory = controllerFactory(component = null) assertThrows(IllegalStateException::class.java) { - activityTransitionAnimator.register(controller) + activityTransitionAnimator.register(factory.cookie, factory) } } @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { - // No TransitionCookie - val controllerWithoutCookie = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = null - } - assertThrows(IllegalStateException::class.java) { - activityTransitionAnimator.register(controllerWithoutCookie) - } - // No ComponentName - val controllerWithoutComponent = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = - ActivityTransitionAnimator.TransitionCookie("test_cookie") - override val component = null - } + var factory = controllerFactory(component = null) assertThrows(IllegalStateException::class.java) { - activityTransitionAnimator.register(controllerWithoutComponent) + activityTransitionAnimator.register(factory.cookie, factory) } // No TransitionRegister @@ -307,14 +269,9 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { testTransitionAnimator, disableWmTimeout = true, ) - val validController = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = - ActivityTransitionAnimator.TransitionCookie("test_cookie") - override val component = ComponentName("com.test.package", "Test") - } + factory = controllerFactory() assertThrows(IllegalStateException::class.java) { - activityTransitionAnimator.register(validController) + activityTransitionAnimator.register(factory.cookie, factory) } } @@ -324,18 +281,12 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun unregistersLongLivedTransition() { - val cookies = arrayOfNulls<ActivityTransitionAnimator.TransitionCookie>(3) for (index in 0 until 3) { - cookies[index] = ActivityTransitionAnimator.TransitionCookie("test_cookie_$index") - - val controller = - object : DelegateTransitionAnimatorController(controller) { - override val transitionCookie = cookies[index] - override val component = ComponentName("foo.bar", "Foobar") - } - activityTransitionAnimator.register(controller) + cookies[index] = mock(ActivityTransitionAnimator.TransitionCookie::class.java) + val factory = controllerFactory(cookies[index]!!) + activityTransitionAnimator.register(factory.cookie, factory) } activityTransitionAnimator.unregister(cookies[0]!!) @@ -350,7 +301,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun doesNotStartIfAnimationIsCancelled() { - val runner = activityTransitionAnimator.createRunner(controller) + val runner = activityTransitionAnimator.createEphemeralRunner(controller) runner.onAnimationCancelled() runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) @@ -364,7 +315,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun cancelsIfNoOpeningWindowIsFound() { - val runner = activityTransitionAnimator.createRunner(controller) + val runner = activityTransitionAnimator.createEphemeralRunner(controller) runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() @@ -377,7 +328,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun startsAnimationIfWindowIsOpening() { - val runner = activityTransitionAnimator.createRunner(controller) + val runner = activityTransitionAnimator.createEphemeralRunner(controller) runner.onAnimationStart( TRANSIT_NONE, arrayOf(fakeWindow()), @@ -404,7 +355,8 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() { assertThrows(IllegalStateException::class.java) { - activityTransitionAnimator.createRunner(controller, longLived = true) + val factory = controllerFactory() + activityTransitionAnimator.createLongLivedRunner(factory, forLaunch = true) } } @@ -414,7 +366,8 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun runnerCreatesDelegateLazily_whenPostingTimeouts() { - val runner = activityTransitionAnimator.createRunner(controller, longLived = true) + val factory = controllerFactory() + val runner = activityTransitionAnimator.createLongLivedRunner(factory, forLaunch = true) assertNull(runner.delegate) runner.postTimeouts() assertNotNull(runner.delegate) @@ -426,29 +379,29 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun runnerCreatesDelegateLazily_onAnimationStart() { - val runner = activityTransitionAnimator.createRunner(controller, longLived = true) + val factory = controllerFactory() + val runner = activityTransitionAnimator.createLongLivedRunner(factory, forLaunch = true) assertNull(runner.delegate) - // The delegate is cleaned up after execution (which happens in another thread), so what we - // do instead is check if it becomes non-null at any point with a 1 second timeout. This - // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false - runBlocking { - val initChecker = launch { - withTimeout(1.seconds) { - while (runner.delegate == null) continue + activityTransitionAnimator.addListener( + object : ActivityTransitionAnimator.Listener { + override fun onTransitionAnimationStart() { + // This is called iff the delegate was initialized, so it's a good proxy for + // checking the initialization. delegateInitialized = true } } - runner.onAnimationStart( - TRANSIT_NONE, - arrayOf(fakeWindow()), - emptyArray(), - emptyArray(), - iCallback, - ) - initChecker.join() - } + ) + runner.onAnimationStart( + TRANSIT_NONE, + arrayOf(fakeWindow()), + emptyArray(), + emptyArray(), + iCallback, + ) + + waitForIdleSync() assertTrue(delegateInitialized) } @@ -458,28 +411,28 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun runnerCreatesDelegateLazily_onAnimationTakeover() { - val runner = activityTransitionAnimator.createRunner(controller, longLived = true) + val factory = controllerFactory() + val runner = activityTransitionAnimator.createLongLivedRunner(factory, forLaunch = false) assertNull(runner.delegate) - // The delegate is cleaned up after execution (which happens in another thread), so what we - // do instead is check if it becomes non-null at any point with a 1 second timeout. This - // will tell us that takeOverWithAnimation() triggered the lazy initialization. var delegateInitialized = false - runBlocking { - val initChecker = launch { - withTimeout(1.seconds) { - while (runner.delegate == null) continue + activityTransitionAnimator.addListener( + object : ActivityTransitionAnimator.Listener { + override fun onTransitionAnimationStart() { + // This is called iff the delegate was initialized, so it's a good proxy for + // checking the initialization. delegateInitialized = true } } - runner.takeOverAnimation( - arrayOf(fakeWindow()), - arrayOf(WindowAnimationState()), - SurfaceControl.Transaction(), - iCallback, - ) - initChecker.join() - } + ) + runner.takeOverAnimation( + arrayOf(fakeWindow(MODE_CLOSING)), + arrayOf(WindowAnimationState()), + SurfaceControl.Transaction(), + iCallback, + ) + + waitForIdleSync() assertTrue(delegateInitialized) } @@ -489,7 +442,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun animationTakeoverThrows_whenTheFlagsAreDisabled() { - val runner = activityTransitionAnimator.createRunner(controller, longLived = false) + val runner = activityTransitionAnimator.createEphemeralRunner(controller) assertThrows(IllegalStateException::class.java) { runner.takeOverAnimation( arrayOf(fakeWindow()), @@ -506,14 +459,28 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { ) @Test fun disposeRunner_delegateDereferenced() { - val runner = activityTransitionAnimator.createRunner(controller) + val runner = activityTransitionAnimator.createEphemeralRunner(controller) assertNotNull(runner.delegate) runner.dispose() waitForIdleSync() assertNull(runner.delegate) } - private fun fakeWindow(): RemoteAnimationTarget { + private fun controllerFactory( + cookie: ActivityTransitionAnimator.TransitionCookie = + mock(ActivityTransitionAnimator.TransitionCookie::class.java), + component: ComponentName? = mock(ComponentName::class.java), + ): ActivityTransitionAnimator.ControllerFactory { + return object : ActivityTransitionAnimator.ControllerFactory(cookie, component) { + override fun createController(forLaunch: Boolean) = + object : DelegateTransitionAnimatorController(controller) { + override val isLaunching: Boolean + get() = forLaunch + } + } + } + + private fun fakeWindow(mode: Int = MODE_OPENING): RemoteAnimationTarget { val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */) val taskInfo = ActivityManager.RunningTaskInfo() taskInfo.topActivity = ComponentName("com.android.systemui", "FakeActivity") @@ -521,7 +488,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { return RemoteAnimationTarget( 0, - RemoteAnimationTarget.MODE_OPENING, + mode, SurfaceControl(), false, Rect(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt index fb0fd23fab24..6bfd08025833 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt @@ -34,8 +34,10 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.model.SysUiState import com.android.systemui.res.R +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock @@ -82,7 +84,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { private val uiProperties = BluetoothTileDialogViewModel.UiProperties.build( isBluetoothEnabled = ENABLED, - isAutoOnToggleFeatureAvailable = ENABLED + isAutoOnToggleFeatureAvailable = ENABLED, ) @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory @Mock private lateinit var dialogManager: SystemUIDialogManager @@ -98,6 +100,8 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { private lateinit var mBluetoothTileDialogDelegate: BluetoothTileDialogDelegate private lateinit var deviceItem: DeviceItem + private val kosmos = testKosmos() + @Before fun setUp() { scheduler = TestCoroutineScheduler() @@ -116,10 +120,16 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { fakeSystemClock, uiEventLogger, logger, - sysuiDialogFactory + sysuiDialogFactory, + kosmos.shadeDialogContextInteractor, ) - whenever(sysuiDialogFactory.create(any(SystemUIDialog.Delegate::class.java))).thenAnswer { + whenever( + sysuiDialogFactory.create( + any(SystemUIDialog.Delegate::class.java), + any() + ) + ).thenAnswer { SystemUIDialog( mContext, 0, @@ -128,7 +138,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { sysuiState, fakeBroadcastDispatcher, dialogTransitionAnimator, - it.getArgument(0) + it.getArgument(0), ) } @@ -140,7 +150,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { deviceName = DEVICE_NAME, connectionSummary = DEVICE_CONNECTION_SUMMARY, iconWithDescription = icon, - background = null + background = null, ) `when`(cachedBluetoothDevice.isBusy).thenReturn(false) } @@ -169,7 +179,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dialog, listOf(deviceItem), showSeeAll = false, - showPairNewDevice = false + showPairNewDevice = false, ) val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list) @@ -217,6 +227,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { uiEventLogger, logger, sysuiDialogFactory, + kosmos.shadeDialogContextInteractor, ) .Adapter(bluetoothTileDialogCallback) .DeviceItemViewHolder(view) @@ -238,7 +249,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dialog, listOf(deviceItem), showSeeAll = false, - showPairNewDevice = true + showPairNewDevice = true, ) val seeAllButton = dialog.requireViewById<View>(R.id.see_all_button) @@ -272,6 +283,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { uiEventLogger, logger, sysuiDialogFactory, + kosmos.shadeDialogContextInteractor, ) .createDialog() dialog.show() @@ -295,6 +307,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { uiEventLogger, logger, sysuiDialogFactory, + kosmos.shadeDialogContextInteractor, ) .createDialog() dialog.show() @@ -318,6 +331,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { uiEventLogger, logger, sysuiDialogFactory, + kosmos.shadeDialogContextInteractor, ) .createDialog() dialog.show() @@ -339,7 +353,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dialog, visibility = VISIBLE, label = null, - isActive = true + isActive = true, ) val audioSharingButton = dialog.requireViewById<View>(R.id.audio_sharing_button) @@ -361,7 +375,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dialog, visibility = VISIBLE, label = null, - isActive = false + isActive = false, ) val audioSharingButton = dialog.requireViewById<View>(R.id.audio_sharing_button) @@ -383,7 +397,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dialog, visibility = GONE, label = null, - isActive = false + isActive = false, ) val audioSharingButton = dialog.requireViewById<View>(R.id.audio_sharing_button) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java index c2c94a88603a..1cabf202463e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java @@ -77,6 +77,8 @@ public class CommunalTouchHandlerTest extends SysuiTestCase { INITIATION_WIDTH, mKosmos.getCommunalInteractor(), mKosmos.getConfigurationInteractor(), + mKosmos.getSceneInteractor(), + Optional.of(mKosmos.getMockWindowRootViewProvider()), mLifecycle ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt index 67e03e4bdb22..82bf5e248a50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt @@ -34,6 +34,7 @@ import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.SystemUIAppComponentFactoryBase import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.dock.DockManagerFake import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags @@ -133,6 +134,7 @@ class CustomizationProviderTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = @@ -203,6 +205,7 @@ class CustomizationProviderTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = testDispatcher, appContext = mContext, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = { kosmos.sceneInteractor }, ) underTest.previewManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index 32fa160fc29f..111d819b5a50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.domain.interactor import android.app.admin.DevicePolicyManager import android.content.Intent import android.os.UserHandle -import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger @@ -30,6 +29,7 @@ import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.dock.DockManagerFake import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.FakeFeatureFlags @@ -64,6 +64,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt @@ -82,7 +83,7 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) @DisableSceneContainer -@FlakyTest(bugId = 292574995, detail = "NullPointer on MockMakerTypeMockability.mockable()") +@Ignore("b/292574995 NullPointer on MockMakerTypeMockability.mockable()") class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { companion object { @@ -270,6 +271,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = @@ -320,6 +322,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = testDispatcher, appContext = mContext, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = { kosmos.sceneInteractor }, ) } @@ -344,7 +347,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { canShowWhileLocked = canShowWhileLocked, ) } else { - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } underTest.onQuickAffordanceTriggered( diff --git a/packages/SystemUI/tests/src/com/android/systemui/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt index 1184a76d54ff..8c00047296d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.dock.DockManagerFake import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.FakeFeatureFlags @@ -81,7 +82,7 @@ import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @FlakyTest( bugId = 292574995, - detail = "on certain architectures all permutations with startActivity=true is causing failures" + detail = "on certain architectures all permutations with startActivity=true is causing failures", ) @SmallTest @RunWith(ParameterizedAndroidJunit4::class) @@ -93,11 +94,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { private val DRAWABLE = mock<Icon> { whenever(this.contentDescription) - .thenReturn( - ContentDescription.Resource( - res = CONTENT_DESCRIPTION_RESOURCE_ID, - ) - ) + .thenReturn(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) } private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337 @@ -273,16 +270,11 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { context = context, userFileManager = mock<UserFileManager>().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) + whenever(getSharedPreferences(anyString(), anyInt(), anyInt())) .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = @@ -316,9 +308,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { underTest = KeyguardQuickAffordanceInteractor( keyguardInteractor = - KeyguardInteractorFactory.create( - featureFlags = featureFlags, - ) + KeyguardInteractorFactory.create(featureFlags = featureFlags) .keyguardInteractor, shadeInteractor = kosmos.shadeInteractor, lockPatternUtils = lockPatternUtils, @@ -335,6 +325,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = testDispatcher, appContext = mContext, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = { kosmos.sceneInteractor }, ) } @@ -350,9 +341,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { homeControls.setState( lockScreenState = - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = DRAWABLE, - ) + KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = DRAWABLE) ) homeControls.onTriggeredResult = if (startActivity) { @@ -361,7 +350,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { canShowWhileLocked = canShowWhileLocked, ) } else { - KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(false) } underTest.onQuickAffordanceTriggered( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt index 3364528f0b54..84976a9d4d39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dock.DockManagerFake import com.android.systemui.flags.FakeFeatureFlags @@ -216,6 +217,7 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + communalSettingsInteractor = kosmos.communalSettingsInteractor, broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = @@ -295,6 +297,7 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() { biometricSettingsRepository = biometricSettingsRepository, backgroundDispatcher = kosmos.testDispatcher, appContext = mContext, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = { kosmos.sceneInteractor }, ), keyguardInteractor = keyguardInteractor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java index b26f0a6e71a3..782b24825bcf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java @@ -557,6 +557,13 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { } @Test + public void startActivityForDialog_always_startActivityWithoutDismissShade() { + mInternetDialogController.startActivityForDialog(mock(Intent.class)); + + verify(mActivityStarter).startActivity(any(Intent.class), eq(false) /* dismissShade */); + } + + @Test public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() { mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java index 300c9b843d1c..8560b67dee33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java @@ -35,6 +35,7 @@ import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.res.R; +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; @@ -149,7 +150,8 @@ public class InternetDialogDelegateTest extends SysuiTestCase { mHandler, mBgExecutor, mKeyguard, - mSystemUIDialogFactory); + mSystemUIDialogFactory, + new FakeShadeDialogContextInteractor(mContext)); mInternetDialogDelegate.createDialog(); mInternetDialogDelegate.onCreate(mSystemUIDialog, null); mInternetDialogDelegate.mAdapter = mInternetAdapter; diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index a0ecb802dd61..f695c13a9e62 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -76,6 +76,8 @@ class UserTrackerImplTest : SysuiTestCase() { @Mock private lateinit var iActivityManager: IActivityManager + @Mock private lateinit var beforeUserSwitchingReply: IRemoteCallback + @Mock private lateinit var userSwitchingReply: IRemoteCallback @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager @@ -199,9 +201,10 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID) + captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() + verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) verify(userManager).getProfiles(newID) @@ -341,10 +344,11 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID) + captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() + verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) assertThat(callback.calledOnUserChanging).isEqualTo(1) assertThat(callback.lastUser).isEqualTo(newID) @@ -395,7 +399,7 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) - captor.value.onBeforeUserSwitching(newID) + captor.value.onBeforeUserSwitching(newID, any()) captor.value.onUserSwitchComplete(newID) runCurrent() @@ -453,8 +457,10 @@ class UserTrackerImplTest : SysuiTestCase() { val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java) verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString()) + captor.value.onBeforeUserSwitching(newID, beforeUserSwitchingReply) captor.value.onUserSwitching(newID, userSwitchingReply) runCurrent() + verify(beforeUserSwitchingReply).sendResult(any()) verify(userSwitchingReply).sendResult(any()) captor.value.onUserSwitchComplete(newID) @@ -488,6 +494,7 @@ class UserTrackerImplTest : SysuiTestCase() { } private class TestCallback : UserTracker.Callback { + var calledOnBeforeUserChanging = 0 var calledOnUserChanging = 0 var calledOnUserChanged = 0 var calledOnProfilesChanged = 0 @@ -495,6 +502,11 @@ class UserTrackerImplTest : SysuiTestCase() { var lastUserContext: Context? = null var lastUserProfiles = emptyList<UserInfo>() + override fun onBeforeUserSwitching(newUser: Int) { + calledOnBeforeUserChanging++ + lastUser = newUser + } + override fun onUserChanging(newUser: Int, userContext: Context) { calledOnUserChanging++ lastUser = newUser 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 041d1a611b55..4b11e2c24722 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.shade import android.content.Context -import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.flag.junit.FlagsParameterization @@ -32,7 +31,6 @@ import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityContainerController import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.systemui.Flags -import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor @@ -406,18 +404,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - @DisableSceneContainer - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun handleDispatchTouchEvent_nsslMigrationOff_userActivity_not_called() { - underTest.setStatusBarViewController(phoneStatusBarViewController) - - interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT) - - verify(centralSurfaces, times(0)).userActivity() - } - - @Test - @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun handleDispatchTouchEvent_nsslMigrationOn_userActivity() { underTest.setStatusBarViewController(phoneStatusBarViewController) @@ -438,7 +424,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun shouldInterceptTouchEvent_dozing_touchNotInLockIconArea_touchIntercepted() { // GIVEN dozing whenever(sysuiStatusBarStateController.isDozing).thenReturn(true) @@ -451,7 +436,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun shouldInterceptTouchEvent_dozing_touchInStatusBar_touchIntercepted() { // GIVEN dozing whenever(sysuiStatusBarStateController.isDozing).thenReturn(true) @@ -464,7 +448,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun shouldInterceptTouchEvent_dozingAndPulsing_touchIntercepted() { // GIVEN dozing whenever(sysuiStatusBarStateController.isDozing).thenReturn(true) @@ -609,7 +592,6 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : } @Test - @EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) fun cancelCurrentTouch_callsDragDownHelper() { underTest.cancelCurrentTouch() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt index 13bc82fa2c70..a04ca038021e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.shade -import android.platform.test.annotations.DisableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.View @@ -27,7 +26,6 @@ import androidx.annotation.IdRes import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT import com.android.systemui.SysuiTestCase import com.android.systemui.fragments.FragmentHostManager import com.android.systemui.fragments.FragmentService @@ -65,10 +63,7 @@ import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -/** - * Uses Flags.KEYGUARD_STATUS_VIEW_MIGRATE_NSSL set to false. If all goes well, this set of tests - * will be deleted. - */ +/** NotificationsQSContainerController tests */ @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest @@ -122,7 +117,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { delayableExecutor, notificationStackScrollLayoutController, ResourcesSplitShadeStateController(), - largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper }, ) overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN) @@ -209,23 +204,23 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = true, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = 0, // taskbar should disappear when shade is expanded expectedNotificationsMargin = NOTIFICATIONS_MARGIN, - expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) given( taskbarVisible = true, navigationMode = BUTTONS_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = STABLE_INSET_BOTTOM, expectedNotificationsMargin = NOTIFICATIONS_MARGIN, - expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) } @@ -237,22 +232,22 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = 0, - expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) given( taskbarVisible = false, navigationMode = BUTTONS_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = 0, // qs goes full height as it's not obscuring nav buttons expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN, - expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) } @@ -263,22 +258,22 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withCutout() + insets = windowInsets().withCutout(), ) then( expectedContainerPadding = CUTOUT_HEIGHT, - expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) given( taskbarVisible = false, navigationMode = BUTTONS_NAVIGATION, - insets = windowInsets().withCutout().withStableBottom() + insets = windowInsets().withCutout().withStableBottom(), ) then( expectedContainerPadding = 0, expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN, - expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET + expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - QS_PADDING_OFFSET, ) } @@ -289,18 +284,18 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = true, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then(expectedContainerPadding = 0, expectedQsPadding = STABLE_INSET_BOTTOM) given( taskbarVisible = true, navigationMode = BUTTONS_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = STABLE_INSET_BOTTOM, - expectedQsPadding = STABLE_INSET_BOTTOM + expectedQsPadding = STABLE_INSET_BOTTOM, ) } @@ -314,19 +309,19 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withCutout().withStableBottom() + insets = windowInsets().withCutout().withStableBottom(), ) then(expectedContainerPadding = CUTOUT_HEIGHT, expectedQsPadding = STABLE_INSET_BOTTOM) given( taskbarVisible = false, navigationMode = BUTTONS_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then( expectedContainerPadding = 0, expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN, - expectedQsPadding = STABLE_INSET_BOTTOM + expectedQsPadding = STABLE_INSET_BOTTOM, ) } @@ -339,7 +334,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then(expectedContainerPadding = 0, expectedNotificationsMargin = 0) @@ -355,7 +350,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { given( taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, - insets = windowInsets().withStableBottom() + insets = windowInsets().withStableBottom(), ) then(expectedContainerPadding = 0) @@ -376,43 +371,6 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { } @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testSplitShadeLayout_isAlignedToGuideline() { - enableSplitShade() - underTest.updateResources() - assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd).isEqualTo(R.id.qs_edge_guideline) - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart) - .isEqualTo(R.id.qs_edge_guideline) - } - - @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testSinglePaneLayout_childrenHaveEqualMargins() { - disableSplitShade() - underTest.updateResources() - val qsStartMargin = getConstraintSetLayout(R.id.qs_frame).startMargin - val qsEndMargin = getConstraintSetLayout(R.id.qs_frame).endMargin - val notifStartMargin = getConstraintSetLayout(R.id.notification_stack_scroller).startMargin - val notifEndMargin = getConstraintSetLayout(R.id.notification_stack_scroller).endMargin - assertThat( - qsStartMargin == qsEndMargin && - notifStartMargin == notifEndMargin && - qsStartMargin == notifStartMargin - ) - .isTrue() - } - - @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testSplitShadeLayout_childrenHaveInsideMarginsOfZero() { - enableSplitShade() - underTest.updateResources() - assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0) - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin) - .isEqualTo(0) - } - - @Test fun testSplitShadeLayout_qsFrameHasHorizontalMarginsOfZero() { enableSplitShade() underTest.updateResources() @@ -421,37 +379,6 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { } @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testLargeScreenLayout_qsAndNotifsTopMarginIsOfHeaderHeightHelper() { - setLargeScreen() - val largeScreenHeaderResourceHeight = 100 - val largeScreenHeaderHelperHeight = 200 - whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()) - .thenReturn(largeScreenHeaderHelperHeight) - overrideResource(R.dimen.large_screen_shade_header_height, largeScreenHeaderResourceHeight) - - // ensure the estimated height (would be 30 here) wouldn't impact this test case - overrideResource(R.dimen.large_screen_shade_header_min_height, 10) - overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 10) - - underTest.updateResources() - - assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin) - .isEqualTo(largeScreenHeaderHelperHeight) - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).topMargin) - .isEqualTo(largeScreenHeaderHelperHeight) - } - - @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testSmallScreenLayout_qsAndNotifsTopMarginIsZero() { - setSmallScreen() - underTest.updateResources() - assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin).isEqualTo(0) - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).topMargin).isEqualTo(0) - } - - @Test fun testSinglePaneShadeLayout_qsFrameHasHorizontalMarginsSetToCorrectValue() { disableSplitShade() underTest.updateResources() @@ -464,17 +391,6 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { } @Test - @DisableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - fun testSinglePaneShadeLayout_isAlignedToParent() { - disableSplitShade() - underTest.updateResources() - assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd) - .isEqualTo(ConstraintSet.PARENT_ID) - assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart) - .isEqualTo(ConstraintSet.PARENT_ID) - } - - @Test fun testAllChildrenOfNotificationContainer_haveIds() { // set dimen to 0 to avoid triggering updating bottom spacing overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, 0) @@ -493,7 +409,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { delayableExecutor, notificationStackScrollLayoutController, ResourcesSplitShadeStateController(), - largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper }, ) controller.updateConstraints() @@ -509,7 +425,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { taskbarVisible = false, navigationMode = GESTURES_NAVIGATION, insets = emptyInsets(), - applyImmediately = false + applyImmediately = false, ) fakeSystemClock.advanceTime(INSET_DEBOUNCE_MILLIS / 2) windowInsetsCallback.accept(windowInsets().withStableBottom()) @@ -576,7 +492,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { taskbarVisible: Boolean, navigationMode: Int, insets: WindowInsets, - applyImmediately: Boolean = true + applyImmediately: Boolean = true, ) { Mockito.clearInvocations(view) taskbarVisibilityCallback.onTaskbarStatusUpdated(taskbarVisible, false) @@ -591,7 +507,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { fun then( expectedContainerPadding: Int, expectedNotificationsMargin: Int = NOTIFICATIONS_MARGIN, - expectedQsPadding: Int = 0 + expectedQsPadding: Int = 0, ) { verify(view).setPadding(anyInt(), anyInt(), anyInt(), eq(expectedContainerPadding)) verify(view).setNotificationsMarginBottom(expectedNotificationsMargin) @@ -623,7 +539,7 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { val layoutParams = ConstraintLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT + ViewGroup.LayoutParams.WRAP_CONTENT, ) // required as cloning ConstraintSet fails if view doesn't have layout params view.layoutParams = layoutParams diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt index 503fa789cb80..1eb88c5a5616 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt @@ -89,6 +89,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { messagingStyle = null, builder = notificationBuilder, systemUiContext = context, + redactText = false, ) // WHEN: binds the viewHolder @@ -149,6 +150,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { messagingStyle = style, builder = notificationBuilder, systemUiContext = context, + redactText = false, ) // WHEN: binds the view SingleLineViewBinder.bind(viewModel, view) @@ -197,6 +199,7 @@ class SingleLineViewBinderTest : SysuiTestCase() { messagingStyle = null, builder = notificationBuilder, systemUiContext = context, + redactText = false, ) // WHEN: binds the view with the view model SingleLineViewBinder.bind(viewModel, view) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt index d3666321c8e4..ef70e277832e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt @@ -379,7 +379,8 @@ class SingleLineViewInflaterTest : SysuiTestCase() { this, if (isConversation) messagingStyle else null, builder, - context + context, + false ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index a91fb45c9c80..e1a891662889 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -1544,14 +1544,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertFalse(mStackScroller.mHeadsUpAnimatingAway); } - @Test - @EnableSceneContainer - public void finishExpanding_sceneContainerEnabled() { - mStackScroller.startOverscrollAfterExpanding(); - verify(mStackScroller.getExpandHelper()).finishExpanding(); - assertTrue(mStackScroller.getIsBeingDragged()); - } - private MotionEvent captureTouchSentToSceneFramework() { ArgumentCaptor<MotionEvent> captor = ArgumentCaptor.forClass(MotionEvent.class); verify(mStackScrollLayoutController).sendTouchToSceneFramework(captor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index eb1e28b891f7..9d6eb798df17 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -65,7 +65,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private float mPanelExpansion; private int mKeyguardStatusBarHeaderHeight; private int mKeyguardStatusHeight; - private int mUserSwitchHeight; private float mDark; private float mQsExpansion; private int mCutoutTopInset = 0; @@ -317,30 +316,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { } @Test - public void notifPaddingAccountsForMultiUserSwitcherInSplitShade() { - setSplitShadeTopMargin(100); - mUserSwitchHeight = 150; - givenLockScreen(); - mIsSplitShade = true; - // WHEN the position algorithm is run - positionClock(); - // THEN the notif padding is split shade top margin + user switch height - assertThat(mClockPosition.stackScrollerPadding).isEqualTo(250); - } - - @Test - public void clockDoesntAccountForMultiUserSwitcherInSplitShade() { - setSplitShadeTopMargin(100); - mUserSwitchHeight = 150; - givenLockScreen(); - mIsSplitShade = true; - // WHEN the position algorithm is run - positionClock(); - // THEN clockY = split shade top margin - assertThat(mClockPosition.clockY).isEqualTo(100); - } - - @Test public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() { givenLockScreen(); mIsSplitShade = true; @@ -370,9 +345,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { mIsSplitShade = false; mBypassEnabled = false; - // mMinTopMargin = 100 = 80 + max(20, 0) - mKeyguardStatusBarHeaderHeight = 80; - mUserSwitchHeight = 20; + mKeyguardStatusBarHeaderHeight = 100; when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)) .thenReturn(0); @@ -636,8 +609,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { mKeyguardStatusBarHeaderHeight, mPanelExpansion, mKeyguardStatusHeight, - mUserSwitchHeight, - 0 /* userSwitchPreferredY */, mDark, ZERO_DRAG, mBypassEnabled, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index b39e38bd71cd..0b4436755fa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -73,6 +73,7 @@ import com.android.systemui.statusbar.phone.ui.DarkIconManager; import com.android.systemui.statusbar.phone.ui.StatusBarIconController; import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewBinder; import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewModel; +import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.StatusBarOperatorNameViewModel; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.statusbar.window.StatusBarWindowStateListener; @@ -1245,7 +1246,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { mSecureSettings = mock(SecureSettings.class); mShadeExpansionStateManager = new ShadeExpansionStateManager(); - mCollapsedStatusBarViewModel = new FakeHomeStatusBarViewModel(); + mCollapsedStatusBarViewModel = new FakeHomeStatusBarViewModel( + mock(StatusBarOperatorNameViewModel.class)); mCollapsedStatusBarViewBinder = new FakeHomeStatusBarViewBinder(); return new CollapsedStatusBarFragment( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt index 320c148f497c..34e06d5dba5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt @@ -48,11 +48,11 @@ import org.mockito.quality.Strictness @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) -class CarrierConfigRepositoryTest : SysuiTestCase() { +class CarrierConfigRepositoryImplTest : SysuiTestCase() { private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) - private lateinit var underTest: CarrierConfigRepository + private lateinit var underTest: CarrierConfigRepositoryImpl private lateinit var mockitoSession: MockitoSession private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable @@ -81,7 +81,7 @@ class CarrierConfigRepositoryTest : SysuiTestCase() { } underTest = - CarrierConfigRepository( + CarrierConfigRepositoryImpl( fakeBroadcastDispatcher, carrierConfigManager, dumpManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 2e0b7c69f092..d7456dfb33c3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -58,6 +58,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy @@ -68,7 +69,6 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiReposito import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture @@ -209,14 +209,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { wifiTableLogBuffer, ) - carrierConfigRepository = - CarrierConfigRepository( - fakeBroadcastDispatcher, - mock(), - mock(), - logger, - testScope.backgroundScope, - ) + carrierConfigRepository = kosmos.carrierConfigRepository connectionFactory = MobileConnectionRepositoryImpl.Factory( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorTest.kt new file mode 100644 index 000000000000..6da8aab4396d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig +import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.createDefaultTestConfig +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CarrierConfigInteractorTest : SysuiTestCase() { + val kosmos = testKosmos() + private val Kosmos.underTest by Kosmos.Fixture { kosmos.carrierConfigInteractor } + + @Test + fun defaultDataSubscriptionCarrierConfig_tracksDefaultSubId() = + kosmos.runTest { + val carrierConfig1 = SystemUiCarrierConfig(1, createDefaultTestConfig()) + val carrierConfig2 = SystemUiCarrierConfig(2, createDefaultTestConfig()) + + // Put some configs in so we can check by identity + carrierConfigRepository.fake.configsById[1] = carrierConfig1 + carrierConfigRepository.fake.configsById[2] = carrierConfig2 + + val latest by collectLastValue(underTest.defaultDataSubscriptionCarrierConfig) + + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + + assertThat(latest).isEqualTo(carrierConfig1) + + fakeMobileIconsInteractor.defaultDataSubId.value = 2 + + assertThat(latest).isEqualTo(carrierConfig2) + } +} 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 76fc61185b49..25d1c377ecbd 100644 --- a/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt +++ b/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt @@ -433,6 +433,8 @@ class FakeStatusBarService : IStatusBarService.Stub() { override fun showRearDisplayDialog(currentBaseState: Int) {} + override fun unbundleNotification(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/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java index 3e44364dc6a0..252c70a61b86 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -342,7 +342,7 @@ public abstract class SysuiTestCase { } /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */ - protected void overrideResource(int resourceId, Object value) { + public void overrideResource(int resourceId, Object value) { mContext.getOrCreateTestableResources().addOverride(resourceId, value); } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt new file mode 100644 index 000000000000..57c8fd066ea8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalBackActionInteractorKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.scene.domain.interactor.sceneInteractor + +val Kosmos.communalBackActionInteractor by + Kosmos.Fixture { + CommunalBackActionInteractor( + communalInteractor = communalInteractor, + communalSceneInteractor = communalSceneInteractor, + sceneInteractor = sceneInteractor, + ) + } 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 ad92b318b0b9..89aad4be7cc0 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 @@ -86,12 +86,8 @@ suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) { } suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean) { - setCommunalV2ConfigEnabled(true) - if (enabled) { - fakeUserRepository.asMainUser() - } else { - fakeUserRepository.asDefaultUser() - } + setCommunalV2ConfigEnabled(enabled) + setCommunalEnabled(enabled) } suspend fun Kosmos.setCommunalAvailable(available: Boolean) { @@ -103,10 +99,6 @@ suspend fun Kosmos.setCommunalAvailable(available: Boolean) { } suspend fun Kosmos.setCommunalV2Available(available: Boolean) { - setCommunalV2ConfigEnabled(true) - setCommunalEnabled(available) - with(fakeKeyguardRepository) { - setIsEncryptedOrLockdown(!available) - setKeyguardShowing(available) - } + setCommunalV2ConfigEnabled(available) + setCommunalAvailable(available) } 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 b407b1ba227a..e3cfb80489e3 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 @@ -17,8 +17,10 @@ package com.android.systemui.communal.ui.viewmodel import android.service.dream.dreamManager +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.plugins.activityStarter import com.android.systemui.statusbar.policy.batteryController val Kosmos.communalToDreamButtonViewModel by @@ -26,6 +28,8 @@ val Kosmos.communalToDreamButtonViewModel by CommunalToDreamButtonViewModel( backgroundContext = testDispatcher, batteryController = batteryController, + settingsInteractor = communalSettingsInteractor, + activityStarter = activityStarter, dreamManager = dreamManager, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt index 534ded57eb85..9012393badd6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt @@ -58,4 +58,26 @@ class FakeDisplayWindowPropertiesRepository(private val context: Context) : fun insert(instance: DisplayWindowProperties) { properties.put(instance.displayId, instance.windowType, instance) } + + /** inserts an entry, mocking everything except the context. */ + fun insertForContext(displayId: Int, windowType: Int, context: Context) { + properties.put( + displayId, + windowType, + DisplayWindowProperties( + displayId = displayId, + windowType = windowType, + context = context, + windowManager = mock(), + layoutInflater = mock(), + ), + ) + } + + /** Whether the repository contains an entry already. */ + fun contains(displayId: Int, windowType: Int): Boolean = + properties.contains(displayId, windowType) + + /** Removes all the entries. */ + fun clear() = properties.clear() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt index 548b5646f5d4..5d206691b520 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt @@ -30,7 +30,7 @@ class FakeKeyguardQuickAffordanceConfig( override val pickerIconResourceId: Int = 0, ) : KeyguardQuickAffordanceConfig { - var onTriggeredResult: OnTriggeredResult = OnTriggeredResult.Handled + var onTriggeredResult: OnTriggeredResult = OnTriggeredResult.Handled(false) private val _lockScreenState = MutableStateFlow<KeyguardQuickAffordanceConfig.LockScreenState>( @@ -41,9 +41,7 @@ class FakeKeyguardQuickAffordanceConfig( override fun pickerName(): String = pickerName - override fun onTriggered( - expandable: Expandable?, - ): OnTriggeredResult { + override fun onTriggered(expandable: Expandable?): OnTriggeredResult { return onTriggeredResult } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt new file mode 100644 index 000000000000..568324832b33 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.data.quickaffordance + +import android.content.applicationContext +import com.android.systemui.communal.data.repository.communalSceneRepository +import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.scene.domain.interactor.sceneInteractor + +val Kosmos.glanceableHubQuickAffordanceConfig by + Kosmos.Fixture { + GlanceableHubQuickAffordanceConfig( + context = applicationContext, + communalInteractor = communalInteractor, + communalSceneRepository = communalSceneRepository, + communalSettingsInteractor = communalSettingsInteractor, + sceneInteractor = sceneInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/LocalUserSelectionManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/LocalUserSelectionManagerKosmos.kt index 21d1a76088fa..328338b88638 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/LocalUserSelectionManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/LocalUserSelectionManagerKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.applicationContext import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.settings.userFileManager import com.android.systemui.settings.userTracker @@ -28,6 +29,7 @@ val Kosmos.localUserSelectionManager by context = applicationContext, userFileManager = userFileManager, userTracker = userTracker, + communalSettingsInteractor = communalSettingsInteractor, broadcastDispatcher = broadcastDispatcher, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceHapticViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceHapticViewModelKosmos.kt new file mode 100644 index 000000000000..d857157137b6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceHapticViewModelKosmos.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.domain.interactor + +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceHapticViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel +import com.android.systemui.kosmos.Kosmos +import kotlinx.coroutines.flow.Flow + +val Kosmos.keyguardQuickAffordanceHapticViewModelFactory by + Kosmos.Fixture { + object : KeyguardQuickAffordanceHapticViewModel.Factory { + override fun create( + quickAffordanceViewModel: Flow<KeyguardQuickAffordanceViewModel> + ): KeyguardQuickAffordanceHapticViewModel = + KeyguardQuickAffordanceHapticViewModel( + quickAffordanceViewModel, + keyguardQuickAffordanceInteractor, + ) + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorKosmos.kt index 009d17e1a329..3b1199a10531 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorKosmos.kt @@ -21,6 +21,7 @@ import android.content.applicationContext import com.android.internal.widget.lockPatternUtils import com.android.keyguard.logging.KeyguardQuickAffordancesLogger import com.android.systemui.animation.dialogTransitionAnimator +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.dock.dockManager import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.biometricSettingsRepository @@ -52,6 +53,7 @@ var Kosmos.keyguardQuickAffordanceInteractor by Fixture { devicePolicyManager = devicePolicyManager, dockManager = dockManager, biometricSettingsRepository = biometricSettingsRepository, + communalSettingsInteractor = communalSettingsInteractor, backgroundDispatcher = testDispatcher, appContext = applicationContext, sceneInteractor = { sceneInteractor }, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index e47310727905..abbfa93edd17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -87,7 +87,6 @@ val Kosmos.keyguardRootViewModel by Fixture { primaryBouncerToLockscreenTransitionViewModel, screenOffAnimationController = screenOffAnimationController, aodBurnInViewModel = aodBurnInViewModel, - aodAlphaViewModel = aodAlphaViewModel, shadeInteractor = shadeInteractor, ) } 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 d941fb049835..43835607c77d 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 @@ -17,6 +17,7 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.mockito.kotlin.verify var Kosmos.testDispatcher by Fixture { StandardTestDispatcher() } @@ -82,6 +83,32 @@ fun <T> TestScope.currentValue(stateFlow: StateFlow<T>): T { } /** Retrieve the current value of this [StateFlow] safely. See `currentValue(TestScope)`. */ +fun <T> Kosmos.currentValue(fn: () -> T) = testScope.currentValue(fn) + +/** + * Retrieve the result of [fn] after running all pending tasks. Do not use to retrieve the value of + * a flow directly; for that, use either `currentValue(StateFlow)` or [collectLastValue] + */ +@OptIn(ExperimentalCoroutinesApi::class) +fun <T> TestScope.currentValue(fn: () -> T): T { + runCurrent() + return fn() +} + +/** Retrieve the result of [fn] after running all pending tasks. See `TestScope.currentValue(fn)` */ fun <T> Kosmos.currentValue(stateFlow: StateFlow<T>): T { return testScope.currentValue(stateFlow) } + +/** Safely verify that a mock has been called after the test scope has caught up */ +@OptIn(ExperimentalCoroutinesApi::class) +fun <T> TestScope.verifyCurrent(mock: T): T { + runCurrent() + return verify(mock) +} + +/** + * Safely verify that a mock has been called after the test scope has caught up. See + * `TestScope.verifyCurrent` + */ +fun <T> Kosmos.verifyCurrent(mock: T) = testScope.verifyCurrent(mock) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 41cfceaa5e38..39f1ad42797b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -63,6 +63,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.scrimStartable import com.android.systemui.scene.sceneContainerConfig import com.android.systemui.scene.shared.model.sceneDataSource +import com.android.systemui.scene.ui.view.mockWindowRootViewProvider import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -191,4 +192,5 @@ class KosmosJavaAdapter() { } val disableFlagsInteractor by lazy { kosmos.disableFlagsInteractor } val fakeDisableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } + val mockWindowRootViewProvider by lazy { kosmos.mockWindowRootViewProvider } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt index ab1c1818bf80..aa29808bd9ee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt @@ -45,7 +45,6 @@ private constructor(failureMetadata: FailureMetadata, subject: QSTileState?) : other ?: return } check("icon").that(actual.icon).isEqualTo(other.icon) - check("iconRes").that(actual.iconRes).isEqualTo(other.iconRes) check("label").that(actual.label).isEqualTo(other.label) check("activationState").that(actual.activationState).isEqualTo(other.activationState) check("secondaryLabel").that(actual.secondaryLabel).isEqualTo(other.secondaryLabel) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt index f52572a9e42d..f5eebb46c2ec 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt @@ -19,13 +19,13 @@ package com.android.systemui.scene.shared.model import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey +import com.android.systemui.kosmos.currentValue import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.TestScope -class FakeSceneDataSource( - initialSceneKey: SceneKey, -) : SceneDataSource { +class FakeSceneDataSource(initialSceneKey: SceneKey, val testScope: TestScope) : SceneDataSource { private val _currentScene = MutableStateFlow(initialSceneKey) override val currentScene: StateFlow<SceneKey> = _currentScene.asStateFlow() @@ -33,18 +33,20 @@ class FakeSceneDataSource( private val _currentOverlays = MutableStateFlow<Set<OverlayKey>>(emptySet()) override val currentOverlays: StateFlow<Set<OverlayKey>> = _currentOverlays.asStateFlow() - var isPaused = false - private set + private var _isPaused = false + val isPaused + get() = testScope.currentValue { _isPaused } - var pendingScene: SceneKey? = null - private set + private var _pendingScene: SceneKey? = null + val pendingScene + get() = testScope.currentValue { _pendingScene } var pendingOverlays: Set<OverlayKey>? = null private set override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) { - if (isPaused) { - pendingScene = toScene + if (_isPaused) { + _pendingScene = toScene } else { _currentScene.value = toScene } @@ -55,7 +57,7 @@ class FakeSceneDataSource( } override fun showOverlay(overlay: OverlayKey, transitionKey: TransitionKey?) { - if (isPaused) { + if (_isPaused) { pendingOverlays = (pendingOverlays ?: currentOverlays.value) + overlay } else { _currentOverlays.value += overlay @@ -63,7 +65,7 @@ class FakeSceneDataSource( } override fun hideOverlay(overlay: OverlayKey, transitionKey: TransitionKey?) { - if (isPaused) { + if (_isPaused) { pendingOverlays = (pendingOverlays ?: currentOverlays.value) - overlay } else { _currentOverlays.value -= overlay @@ -82,9 +84,9 @@ class FakeSceneDataSource( * last one will be remembered. */ fun pause() { - check(!isPaused) { "Can't pause what's already paused!" } + check(!_isPaused) { "Can't pause what's already paused!" } - isPaused = true + _isPaused = true } /** @@ -100,15 +102,12 @@ class FakeSceneDataSource( * * If [expectedScene] is provided, will assert that it's indeed the latest called. */ - fun unpause( - force: Boolean = false, - expectedScene: SceneKey? = null, - ) { - check(force || isPaused) { "Can't unpause what's already not paused!" } - - isPaused = false - pendingScene?.let { _currentScene.value = it } - pendingScene = null + fun unpause(force: Boolean = false, expectedScene: SceneKey? = null) { + check(force || _isPaused) { "Can't unpause what's already not paused!" } + + _isPaused = false + _pendingScene?.let { _currentScene.value = it } + _pendingScene = null pendingOverlays?.let { _currentOverlays.value = it } pendingOverlays = null diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneDataSourceKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneDataSourceKosmos.kt index f5196866ae6f..7eebfc305682 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneDataSourceKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneDataSourceKosmos.kt @@ -19,13 +19,12 @@ package com.android.systemui.scene.shared.model 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.scene.initialSceneKey import com.android.systemui.scene.sceneContainerConfig val Kosmos.fakeSceneDataSource by Fixture { - FakeSceneDataSource( - initialSceneKey = initialSceneKey, - ) + FakeSceneDataSource(initialSceneKey = initialSceneKey, testScope = testScope) } val Kosmos.sceneDataSourceDelegator by Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKosmos.kt index 5c91dc80b3d4..e6ba9a581836 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKosmos.kt @@ -17,6 +17,9 @@ package com.android.systemui.scene.ui.view import com.android.systemui.kosmos.Kosmos +import javax.inject.Provider import org.mockito.kotlin.mock val Kosmos.mockShadeRootView by Kosmos.Fixture { mock<WindowRootView>() } +val Kosmos.mockWindowRootViewProvider by + Kosmos.Fixture { Provider<WindowRootView> { mock<WindowRootView>() } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/NotificationShadeWindowViewKosmos.kt index 13fde9608017..18c44bac3ff1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/NotificationShadeWindowViewKosmos.kt @@ -14,10 +14,9 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.shared.domain.interactor +package com.android.systemui.shade import com.android.systemui.kosmos.Kosmos -import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor +import org.mockito.kotlin.mock -val Kosmos.collapsedStatusBarInteractor: CollapsedStatusBarInteractor by - Kosmos.Fixture { CollapsedStatusBarInteractor(disableFlagsInteractor) } +var Kosmos.notificationShadeWindowView by Kosmos.Fixture { mock<NotificationShadeWindowView>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt index 4dcd2208b152..3ed730271bc3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt @@ -16,6 +16,14 @@ package com.android.systemui.shade.data.repository +import android.content.applicationContext import com.android.systemui.kosmos.Kosmos +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock val Kosmos.shadeAnimationRepository by Kosmos.Fixture { ShadeAnimationRepository() } +val Kosmos.shadeDialogContextInteractor by + Kosmos.Fixture { + mock<ShadeDialogContextInteractor> { on { context } doReturn applicationContext } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt index 8865573c4030..9f4091ccfc26 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionControllerKosmos.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt index e4a3896378f6..1a451ce01525 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerKosmos.kt @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.phone.lsShadeTransitionLogger import com.android.systemui.statusbar.policy.configurationController import com.android.systemui.statusbar.policy.splitShadeStateController -val Kosmos.lockscreenShadeTransitionController by Fixture { +var Kosmos.lockscreenShadeTransitionController by Fixture { LockscreenShadeTransitionController( statusBarStateController = sysuiStatusBarStateController, logger = lsShadeTransitionLogger, @@ -62,6 +62,6 @@ val Kosmos.lockscreenShadeTransitionController by Fixture { splitShadeStateController = splitShadeStateController, shadeLockscreenInteractorLazy = { shadeLockscreenInteractor }, naturalScrollingSettingObserver = naturalScrollingSettingObserver, - lazyQSSceneAdapter = { qsSceneAdapter } + lazyQSSceneAdapter = { qsSceneAdapter }, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt index 5523bd68f692..8a68eef2f371 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerKosmos.kt @@ -20,10 +20,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import org.mockito.kotlin.mock -var Kosmos.singleShadeLockScreenOverScroller by Fixture { - mock<SingleShadeLockScreenOverScroller>() -} - var Kosmos.singleShadeLockScreenOverScrollerFactory by Fixture { - SingleShadeLockScreenOverScroller.Factory { _ -> singleShadeLockScreenOverScroller } + mock<SingleShadeLockScreenOverScroller.Factory>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt new file mode 100644 index 000000000000..62cdc87f980f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope + +val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by + Kosmos.Fixture { StatusBarPopupChipsViewModel(testScope.backgroundScope) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationContentExtractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationContentExtractor.kt new file mode 100644 index 000000000000..680e0de22794 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationContentExtractor.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted + +import android.app.Notification +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import org.junit.Assert + +class FakePromotedNotificationContentExtractor : PromotedNotificationContentExtractor { + @JvmField + val contentForEntry = mutableMapOf<NotificationEntry, PromotedNotificationContentModel?>() + @JvmField val extractCalls = mutableListOf<Pair<NotificationEntry, Notification.Builder>>() + + override fun extractContent( + entry: NotificationEntry, + recoveredBuilder: Notification.Builder, + ): PromotedNotificationContentModel? { + extractCalls.add(entry to recoveredBuilder) + + if (contentForEntry.isEmpty()) { + // If *no* entries are set, just return null for everything. + return null + } else { + // If entries *are* set, fail on unexpected ones. + Assert.assertTrue(contentForEntry.containsKey(entry)) + return contentForEntry.get(entry) + } + } + + fun resetForEntry(entry: NotificationEntry, content: PromotedNotificationContentModel?) { + contentForEntry.clear() + contentForEntry.put(entry, content) + extractCalls.clear() + } + + fun verifyZeroExtractCalls() { + Assert.assertTrue(extractCalls.isEmpty()) + } + + fun verifyOneExtractCall() { + Assert.assertEquals(1, extractCalls.size) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt index 88caf6e2ba30..ea7b41d43871 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/FakePromotedNotificationsProvider.kt @@ -17,11 +17,20 @@ package com.android.systemui.statusbar.notification.promoted import com.android.systemui.statusbar.notification.collection.NotificationEntry +import org.junit.Assert class FakePromotedNotificationsProvider : PromotedNotificationsProvider { val promotedEntries = mutableSetOf<NotificationEntry>() + val shouldPromoteForEntry = mutableMapOf<NotificationEntry, Boolean>() override fun shouldPromote(entry: NotificationEntry): Boolean { - return promotedEntries.contains(entry) + if (shouldPromoteForEntry.isEmpty()) { + // If *no* entries are set, just return false for everything. + return false + } else { + // If entries *are* set, fail on unexpected ones. + Assert.assertTrue(shouldPromoteForEntry.containsKey(entry)) + return shouldPromoteForEntry[entry] ?: false + } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt index 5e9f12b4b1cc..52c17c82fb12 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt @@ -21,7 +21,7 @@ import com.android.systemui.kosmos.Kosmos var Kosmos.promotedNotificationContentExtractor by Kosmos.Fixture { - PromotedNotificationContentExtractor( + PromotedNotificationContentExtractorImpl( promotedNotificationsProvider, applicationContext, promotedNotificationLogger, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt index 7126933154df..e739e82aa8a8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt @@ -65,7 +65,7 @@ import com.android.systemui.statusbar.notification.headsup.HeadsUpManager import com.android.systemui.statusbar.notification.icon.IconBuilder import com.android.systemui.statusbar.notification.icon.IconManager import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractorImpl import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProviderImpl import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.CoordinateOnClickListener @@ -222,16 +222,11 @@ class ExpandableNotificationRowBuilder( Mockito.mock(LauncherApps::class.java, STUB_ONLY), Mockito.mock(ConversationNotificationManager::class.java, STUB_ONLY), ) - - val promotedNotificationsProvider = PromotedNotificationsProviderImpl() - val promotedNotificationLog = logcatLogBuffer("PromotedNotifLog") - val promotedNotificationLogger = PromotedNotificationLogger(promotedNotificationLog) - val promotedNotificationContentExtractor = - PromotedNotificationContentExtractor( - promotedNotificationsProvider, + PromotedNotificationContentExtractorImpl( + PromotedNotificationsProviderImpl(), context, - promotedNotificationLogger, + PromotedNotificationLogger(logcatLogBuffer("PromotedNotifLog")), ) mContentBinder = diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryKosmos.kt new file mode 100644 index 000000000000..02ae3ad03dad --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryKosmos.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.airplane.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.airplaneModeRepository by Kosmos.Fixture { FakeAirplaneModeRepository() } + +val AirplaneModeRepository.fake + get() = this as FakeAirplaneModeRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/FakeAirplaneModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/FakeAirplaneModeRepository.kt index 74b2da49d43f..c30124c1f1cb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/FakeAirplaneModeRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/FakeAirplaneModeRepository.kt @@ -17,14 +17,12 @@ package com.android.systemui.statusbar.pipeline.airplane.data.repository import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow class FakeAirplaneModeRepository : AirplaneModeRepository { - private val _isAirplaneMode = MutableStateFlow(false) - override val isAirplaneMode: StateFlow<Boolean> = _isAirplaneMode + override val isAirplaneMode = MutableStateFlow(false) override suspend fun setIsAirplaneMode(isEnabled: Boolean) { - _isAirplaneMode.value = isEnabled + isAirplaneMode.value = isEnabled } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt index 99ed4f0db64d..62d7601d7232 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt @@ -17,15 +17,15 @@ package com.android.systemui.statusbar.pipeline.airplane.domain.interactor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository +import com.android.systemui.statusbar.pipeline.airplane.data.repository.airplaneModeRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by Kosmos.Fixture { AirplaneModeInteractor( - FakeAirplaneModeRepository(), - FakeConnectivityRepository(), + airplaneModeRepository, + connectivityRepository, mobileConnectionsRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt new file mode 100644 index 000000000000..a6431afe6592 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.carrierConfigRepository: CarrierConfigRepository by Fixture { + FakeCarrierConfigRepository() +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt new file mode 100644 index 000000000000..adf6ca1d1710 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.data.repository + +import android.os.PersistableBundle +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig + +class FakeCarrierConfigRepository : CarrierConfigRepository { + override suspend fun startObservingCarrierConfigUpdates() {} + + val configsById = mutableMapOf<Int, SystemUiCarrierConfig>() + + override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig = + configsById.getOrPut(subId) { SystemUiCarrierConfig(subId, createDefaultTestConfig()) } +} + +val CarrierConfigRepository.fake + get() = this as FakeCarrierConfigRepository + +fun createDefaultTestConfig() = + PersistableBundle().also { + it.putBoolean( + android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, + false, + ) + it.putBoolean( + android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, + false, + ) + it.putBoolean(android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL, true) + } + +/** Override the default config with the given (key, value) pair */ +fun configWithOverride(key: String, override: Boolean): PersistableBundle = + createDefaultTestConfig().also { it.putBoolean(key, override) } + +/** Override any number of configs from the default */ +fun configWithOverrides(vararg overrides: Pair<String, Boolean>) = + createDefaultTestConfig().also { config -> + overrides.forEach { (key, value) -> config.putBoolean(key, value) } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorKosmos.kt new file mode 100644 index 000000000000..7cb2750ef765 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/CarrierConfigInteractorKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository + +val Kosmos.carrierConfigInteractor by + Kosmos.Fixture { + CarrierConfigInteractor( + carrierConfigRepository, + mobileIconsInteractor, + applicationCoroutineScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt index 3a4bf8e48d33..3b8adb4a8307 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt @@ -55,10 +55,13 @@ class FakeMobileIconsInteractor( override val filteredSubscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf()) + override val defaultDataSubId = MutableStateFlow(DEFAULT_DATA_SUB_ID) + private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false) override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled - override val activeDataIconInteractor = MutableStateFlow(null) + override val activeDataIconInteractor: MutableStateFlow<MobileIconInteractor?> = + MutableStateFlow(null) override val alwaysShowDataRatIcon = MutableStateFlow(false) @@ -83,13 +86,14 @@ class FakeMobileIconsInteractor( override val isDeviceInEmergencyCallsOnlyMode = MutableStateFlow(false) - /** Always returns a new fake interactor */ override fun getMobileConnectionInteractorForSubId(subId: Int): FakeMobileIconInteractor { - return FakeMobileIconInteractor(tableLogBuffer).also { - interactorCache[subId] = it - // Also update the icons - icons.value = interactorCache.values.toList() - } + return interactorCache + .getOrElse(subId) { FakeMobileIconInteractor(tableLogBuffer) } + .also { + interactorCache[subId] = it + // Also update the icons + icons.value = interactorCache.values.toList() + } } /** diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstantsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstantsKosmos.kt new file mode 100644 index 000000000000..3bdddf8b9a0b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstantsKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.connectivityConstants by Kosmos.Fixture { FakeConnectivityConstnants() } + +class FakeConnectivityConstnants : ConnectivityConstants { + override var hasDataCapabilities: Boolean = true + + override var shouldShowActivityConfig: Boolean = false +} + +val ConnectivityConstants.fake + get() = this as FakeConnectivityConstnants diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorKosmos.kt new file mode 100644 index 000000000000..39fff0fd5e81 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarIconBlockListInteractorKosmos.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.domain.interactor + +import android.content.res.mainResources +import android.provider.Settings +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testCase +import com.android.systemui.res.R +import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository +import com.android.systemui.shared.settings.data.repository.secureSettingsRepository + +val Kosmos.homeStatusBarIconBlockListInteractor by + Kosmos.Fixture { HomeStatusBarIconBlockListInteractor(mainResources, secureSettingsRepository) } + +/** + * [icons] can be a list of icons that should appear on the blocklist. Note that this should be + * called before instantiating your class dependent on this list, since it overrides resources and + * is not reactive to resource changes. + */ +suspend fun Kosmos.setHomeStatusBarIconBlockList(icons: List<String>) { + var volBlocked = false + val otherIcons = mutableListOf<String>() + icons.forEach { icon -> + if (icon.lowercase() == "volume") { + volBlocked = true + } else { + otherIcons.add(icon) + } + } + + fakeSecureSettingsRepository.setInt( + Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, + if (volBlocked) 0 else 1, + ) + + testCase.overrideResource( + R.array.config_collapsed_statusbar_icon_blocklist, + otherIcons.toTypedArray(), + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorKosmos.kt new file mode 100644 index 000000000000..c1b66816b37a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/HomeStatusBarInteractorKosmos.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.domain.interactor + +import android.telephony.CarrierConfigManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor +import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.airplaneModeInteractor +import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig +import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.configWithOverride +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.carrierConfigInteractor +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor + +val Kosmos.homeStatusBarInteractor: HomeStatusBarInteractor by + Kosmos.Fixture { + HomeStatusBarInteractor( + airplaneModeInteractor, + carrierConfigInteractor, + disableFlagsInteractor, + ) + } + +/** Set the default data subId to 1, and sets the carrier config setting to [show] */ +fun Kosmos.setHomeStatusBarInteractorShowOperatorName(show: Boolean) { + fakeMobileIconsInteractor.defaultDataSubId.value = 1 + carrierConfigRepository.fake.configsById[1] = + SystemUiCarrierConfig( + 1, + configWithOverride(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, show), + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt index eb17237afbb5..924b6b43b49a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt @@ -27,18 +27,23 @@ import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsVie import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor +import com.android.systemui.statusbar.phone.domain.interactor.darkIconInteractor import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor -import com.android.systemui.statusbar.pipeline.shared.domain.interactor.collapsedStatusBarInteractor +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarIconBlockListInteractor +import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarInteractor -val Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by +var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by Kosmos.Fixture { HomeStatusBarViewModelImpl( - collapsedStatusBarInteractor, + homeStatusBarInteractor, + homeStatusBarIconBlockListInteractor, lightsOutInteractor, activeNotificationsInteractor, + darkIconInteractor, headsUpNotificationInteractor, keyguardTransitionInteractor, keyguardInteractor, + statusBarOperatorNameViewModel, sceneInteractor, sceneContainerOcclusionInteractor, shadeInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelKosmos.kt new file mode 100644 index 000000000000..5887e3c323d9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/StatusBarOperatorNameViewModelKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.mobileIconsInteractor + +val Kosmos.statusBarOperatorNameViewModel by + Kosmos.Fixture { StatusBarOperatorNameViewModel(mobileIconsInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateKosmos.kt index 932e768676cb..6c98d19db5d7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogDelegateKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.animation.dialogTransitionAnimator import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.mainCoroutineContext import com.android.systemui.plugins.activityStarter +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.phone.systemUIDialogFactory import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.modesDialogViewModel import com.android.systemui.util.mockito.mock @@ -35,5 +36,6 @@ var Kosmos.modesDialogDelegate: ModesDialogDelegate by { modesDialogViewModel }, modesDialogEventLogger, mainCoroutineContext, + shadeDialogContextInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt index a3572754ab19..f31697e82a45 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt @@ -70,6 +70,14 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { } } + fun getContentObservers(uri: Uri, userHandle: Int): List<ContentObserver> { + if (userHandle == UserHandle.USER_ALL) { + return contentObserversAllUsers[uri.toString()] ?: listOf() + } else { + return contentObservers[SettingsKey(userHandle, uri.toString())] ?: listOf() + } + } + override fun getContentResolver(): ContentResolver { throw UnsupportedOperationException("FakeSettings.getContentResolver is not implemented") } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt index 34661ced71b2..4fda95bab2ec 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt @@ -22,6 +22,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyInteractor +import com.android.systemui.statusbar.policy.configurationController import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor import com.android.systemui.volume.dialog.ringer.domain.volumeDialogRingerInteractor import com.android.systemui.volume.dialog.shared.volumeDialogLogger @@ -37,5 +38,6 @@ val Kosmos.volumeDialogRingerDrawerViewModel by vibrator = vibratorHelper, volumeDialogLogger = volumeDialogLogger, visibilityInteractor = volumeDialogVisibilityInteractor, + configurationController = configurationController, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractorKosmos.kt index 423100a1addf..44917dd4ba48 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSliderInteractorKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.dialog.sliders.domain.interactor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.volumeDialogController import com.android.systemui.volume.dialog.domain.interactor.volumeDialogStateInteractor import com.android.systemui.volume.dialog.sliders.domain.model.volumeDialogSliderType @@ -25,6 +26,7 @@ val Kosmos.volumeDialogSliderInteractor: VolumeDialogSliderInteractor by Kosmos.Fixture { VolumeDialogSliderInteractor( volumeDialogSliderType, + applicationCoroutineScope, volumeDialogStateInteractor, volumeDialogController, ) diff --git a/packages/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java b/packages/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java index 3638429f33fb..a760b12ac8a1 100644 --- a/packages/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java +++ b/packages/Vcn/framework-b/src/android/net/vcn/VcnTransportInfo.java @@ -161,7 +161,14 @@ public final class VcnTransportInfo implements TransportInfo, Parcelable { return 0; } - /** @hide */ + /** + * Create a copy of a {@link VcnTransportInfo} with some fields redacted based on the + * permissions held by the receiving app. + * + * @param redactions bitmask of redactions that needs to be performed on this instance. + * @return the copy of this instance with the necessary redactions. + * @hide + */ @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 3441d94facda..9ceca5d1dbfe 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1589,7 +1589,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ * lock because this calls out to WindowManagerService. */ void addWindowTokensForAllDisplays() { - final Display[] displays = mDisplayManager.getDisplays(); + Display[] displays = {}; + final long identity = Binder.clearCallingIdentity(); + try { + displays = mDisplayManager.getDisplays(); + } finally { + Binder.restoreCallingIdentity(identity); + } for (int i = 0; i < displays.length; i++) { final int displayId = displays[i].getDisplayId(); addWindowTokenForDisplay(displayId); @@ -1625,7 +1631,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } public void onRemoved() { - final Display[] displays = mDisplayManager.getDisplays(); + Display[] displays = {}; + final long identity = Binder.clearCallingIdentity(); + try { + displays = mDisplayManager.getDisplays(); + } finally { + Binder.restoreCallingIdentity(identity); + } for (int i = 0; i < displays.length; i++) { final int displayId = displays[i].getDisplayId(); onDisplayRemoved(displayId); diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 3025e2eaede0..549f8fa77b53 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -217,6 +217,13 @@ public class UserBackupManagerService { + mPowerManagerWakeLock.getTag())); return; } + + if (!mPowerManagerWakeLock.isHeld()) { + Slog.w(TAG, addUserIdToLogMessage(mUserId, + "Wakelock not held: " + mPowerManagerWakeLock.getTag())); + return; + } + mPowerManagerWakeLock.release(); Slog.v( TAG, diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java index fd18fa856916..abfb8268bd9a 100644 --- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java +++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java @@ -55,6 +55,7 @@ import android.content.Intent; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; +import android.media.AudioManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -102,6 +103,7 @@ public class ContextualSearchManagerService extends SystemService { private final PackageManagerInternal mPackageManager; private final WindowManagerInternal mWmInternal; private final DevicePolicyManagerInternal mDpmInternal; + private final AudioManager mAudioManager; private final Object mLock = new Object(); private final AssistDataRequester mAssistDataRequester; @@ -163,6 +165,8 @@ public class ContextualSearchManagerService extends SystemService { mAtmInternal = Objects.requireNonNull( LocalServices.getService(ActivityTaskManagerInternal.class)); mPackageManager = LocalServices.getService(PackageManagerInternal.class); + mAudioManager = context.getSystemService(AudioManager.class); + mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class)); mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class); mAssistDataRequester = new AssistDataRequester( @@ -306,6 +310,10 @@ public class ContextualSearchManagerService extends SystemService { SystemClock.uptimeMillis()); launchIntent.putExtra(ContextualSearchManager.EXTRA_ENTRYPOINT, entrypoint); launchIntent.putExtra(ContextualSearchManager.EXTRA_TOKEN, mToken); + if (Flags.includeAudioPlayingStatus()) { + launchIntent.putExtra(ContextualSearchManager.EXTRA_IS_AUDIO_PLAYING, + mAudioManager.isMusicActive()); + } boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed(); final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities(); final List<IBinder> activityTokens = new ArrayList<>(records.size()); diff --git a/services/core/Android.bp b/services/core/Android.bp index 06f9e2bf55b2..dc830642dcc5 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -229,7 +229,6 @@ java_library_static { "power_hint_flags_lib", "biometrics_flags_lib", "am_flags_lib", - "updates_flags_lib", "com_android_server_accessibility_flags_lib", "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib", "com_android_launcher3_flags_lib", diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index c15cf34b8955..6858e2941ff9 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -31,6 +31,7 @@ per-file *Storage* = file:/core/java/android/os/storage/OWNERS per-file *TimeUpdate* = file:/services/core/java/com/android/server/timezonedetector/OWNERS per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS +per-file GestureLauncherService.java = file:/INPUT_OWNERS per-file MmsServiceBroker.java = file:/telephony/OWNERS per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS per-file PackageWatchdog.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 719928b8e582..09440e0e997d 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -5266,6 +5266,22 @@ public class AccountManagerService } } + @Override + public void onNullBinding(ComponentName name) { + IAccountManagerResponse response = getResponseAndClose(); + if (response != null) { + try { + response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, + "disconnected"); + } catch (RemoteException e) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Session.onNullBinding: " + + "caught RemoteException while responding", e); + } + } + } + } + public abstract void run() throws RemoteException; public void onTimedOut() { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 4944cafeb83d..4b8770b3cd35 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RECONFIGURATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; @@ -31,6 +32,7 @@ import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROA import static com.android.server.am.BroadcastConstants.getDeviceConfigBoolean; import android.annotation.NonNull; +import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.ForegroundServiceTypePolicy; import android.content.ComponentName; @@ -55,6 +57,7 @@ import android.util.SparseBooleanArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; import dalvik.annotation.optimization.NeverCompile; @@ -181,6 +184,12 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = "follow_up_oomadj_update_wait_duration"; + /* + * Oom score cutoff beyond which any process that does not have the CPU_TIME capability will be + * frozen. + */ + static final String KEY_FREEZER_CUTOFF_ADJ = "freezer_cutoff_adj"; + private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024; private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true; private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000; @@ -267,6 +276,9 @@ final class ActivityManagerConstants extends ContentObserver { */ private static final long DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = 1000L; + /** The default value to {@link #KEY_FREEZER_CUTOFF_ADJ} */ + private static final int DEFAULT_FREEZER_CUTOFF_ADJ = ProcessList.CACHED_APP_MIN_ADJ; + /** * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} */ @@ -1171,6 +1183,14 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION; /** + * The cutoff adj for the freezer, app processes with adj greater than this value will be + * eligible for the freezer. + * + * @see #KEY_FREEZER_CUTOFF_ADJ + */ + public int FREEZER_CUTOFF_ADJ = DEFAULT_FREEZER_CUTOFF_ADJ; + + /** * Indicates whether PSS profiling in AppProfiler is disabled or not. */ static final String KEY_DISABLE_APP_PROFILER_PSS_PROFILING = @@ -1194,6 +1214,7 @@ final class ActivityManagerConstants extends ContentObserver { new OnPropertiesChangedListener() { @Override public void onPropertiesChanged(Properties properties) { + boolean oomAdjusterConfigUpdated = false; for (String name : properties.getKeyset()) { if (name == null) { return; @@ -1372,6 +1393,11 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_TIERED_CACHED_ADJ_UI_TIER_SIZE: updateUseTieredCachedAdj(); break; + case KEY_FREEZER_CUTOFF_ADJ: + FREEZER_CUTOFF_ADJ = properties.getInt(KEY_FREEZER_CUTOFF_ADJ, + DEFAULT_FREEZER_CUTOFF_ADJ); + oomAdjusterConfigUpdated = true; + break; case KEY_DISABLE_APP_PROFILER_PSS_PROFILING: updateDisableAppProfilerPssProfiling(); break; @@ -1389,6 +1415,13 @@ final class ActivityManagerConstants extends ContentObserver { break; } } + if (oomAdjusterConfigUpdated) { + final ActivityManagerInternal ami = LocalServices.getService( + ActivityManagerInternal.class); + if (ami != null) { + ami.updateOomAdj(OOM_ADJ_REASON_RECONFIGURATION); + } + } } }; @@ -2534,6 +2567,9 @@ final class ActivityManagerConstants extends ContentObserver { pw.print(" "); pw.print(KEY_ENABLE_NEW_OOMADJ); pw.print("="); pw.println(ENABLE_NEW_OOMADJ); + pw.print(" "); pw.print(KEY_FREEZER_CUTOFF_ADJ); + pw.print("="); pw.println(FREEZER_CUTOFF_ADJ); + pw.print(" "); pw.print(KEY_DISABLE_APP_PROFILER_PSS_PROFILING); pw.print("="); pw.println(APP_PROFILER_PSS_PROFILING_DISABLED); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cd929c1883d0..50b6990c0c1c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4799,9 +4799,6 @@ public class ActivityManagerService extends IActivityManager.Stub updateLruProcessLocked(app, false, null); checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); - updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN); - checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked"); - final long now = SystemClock.uptimeMillis(); synchronized (mAppProfiler.mProfilerLock) { app.mProfile.setLastRequestedGc(now); @@ -4815,6 +4812,15 @@ public class ActivityManagerService extends IActivityManager.Stub } mProcessesOnHold.remove(app); + // See if the top visible activity is waiting to run in this process... + if (com.android.server.am.Flags.expediteActivityLaunchOnColdStart()) { + if (normalMode) { + mAtmInternal.attachApplication(app.getWindowProcessController()); + } + } + updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN); + checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked"); + if (!mConstants.mEnableWaitForFinishAttachApplication) { finishAttachApplicationInner(startSeq, callingUid, pid); } @@ -4880,18 +4886,21 @@ public class ActivityManagerService extends IActivityManager.Stub // Mark the finish attach application phase as completed mProcessStateController.setPendingFinishAttach(app, false); - final boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); final String processName = app.processName; boolean badApp = false; boolean didSomething = false; - // See if the top visible activity is waiting to run in this process... - if (normalMode) { - try { - didSomething = mAtmInternal.attachApplication(app.getWindowProcessController()); - } catch (Exception e) { - Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); - badApp = true; + if (!com.android.server.am.Flags.expediteActivityLaunchOnColdStart()) { + final boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); + + if (normalMode) { + try { + didSomething |= mAtmInternal.attachApplication( + app.getWindowProcessController()); + } catch (Exception e) { + Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); + badApp = true; + } } } @@ -19387,9 +19396,6 @@ public class ActivityManagerService extends IActivityManager.Stub creatorPackage); if (creatorToken != null) { extraIntent.setCreatorToken(creatorToken); - // TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329 - Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: " - + creatorPackage + "; intent: " + extraIntent); FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, false); } }); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 9a63546bf5a7..cbebc905796c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -449,6 +449,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runSetAppZygotePreloadTimeout(pw); case "set-media-foreground-service": return runSetMediaForegroundService(pw); + case "clear-bad-process": + return runClearBadProcess(pw); default: return handleDefaultCommands(cmd); } @@ -4276,6 +4278,27 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + int runClearBadProcess(PrintWriter pw) throws RemoteException { + final String processName = getNextArgRequired(); + int userId = UserHandle.USER_CURRENT; + String opt; + while ((opt = getNextOption()) != null) { + if ("--user".equals(opt)) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: unknown option " + opt); + return -1; + } + } + if (userId == UserHandle.USER_CURRENT) { + userId = mInternal.getCurrentUserId(); + } + + pw.println("Clearing '" + processName + "' in u" + userId + " from bad processes list"); + mInternal.mAppErrors.clearBadProcessForUser(processName, userId); + return 0; + } + private Resources getResources(PrintWriter pw) throws RemoteException { // system resources does not contain all the device configuration, construct it manually. Configuration config = mInterface.getConfiguration(); @@ -4717,6 +4740,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" set-media-foreground-service inactive|active [--user USER_ID] <PACKAGE>" + " <NOTIFICATION_ID>"); pw.println(" Set an app's media service inactive or active."); + pw.println(" clear-bad-process [--user USER_ID] <PROCESS_NAME>"); + pw.println(" Clears a process from the bad processes list."); Intent.printIntentArgsHelp(pw, ""); } } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index b7a5f3e4099a..2fbf05eb0061 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -373,6 +373,24 @@ class AppErrors { } } + void clearBadProcessForUser(final String processName, final int userId) { + synchronized (mBadProcessLock) { + final ProcessMap<BadProcessInfo> badProcesses = new ProcessMap<>(); + badProcesses.putAll(mBadProcesses); + final SparseArray<BadProcessInfo> uids = badProcesses.get(processName); + if (uids == null) { + return; + } + for (int i = uids.size() - 1; i >= 0; --i) { + final int uid = uids.keyAt(i); + if (userId == UserHandle.USER_ALL || userId == UserHandle.getUserId(uid)) { + badProcesses.remove(processName, uid); + } + } + mBadProcesses = badProcesses; + } + } + void markBadProcess(final String processName, final int uid, BadProcessInfo info) { synchronized (mBadProcessLock) { final ProcessMap<BadProcessInfo> badProcesses = new ProcessMap<>(); diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 2f5362f53361..d335529a006a 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -25,9 +25,11 @@ import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FOLLOW_UP; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RECONFIGURATION; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; @@ -203,6 +205,10 @@ public class CachedAppOptimizer { FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_RESTRICTION_CHANGE; static final int UNFREEZE_REASON_COMPONENT_DISABLED = FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_COMPONENT_DISABLED; + static final int UNFREEZE_REASON_OOM_ADJ_FOLLOW_UP = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_OOM_ADJ_FOLLOW_UP; + static final int UNFREEZE_REASON_OOM_ADJ_RECONFIGURATION = + FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_OOM_ADJ_RECONFIGURATION; @IntDef(prefix = {"UNFREEZE_REASON_"}, value = { UNFREEZE_REASON_NONE, @@ -234,6 +240,8 @@ public class CachedAppOptimizer { UNFREEZE_REASON_EXECUTING_SERVICE, UNFREEZE_REASON_RESTRICTION_CHANGE, UNFREEZE_REASON_COMPONENT_DISABLED, + UNFREEZE_REASON_OOM_ADJ_FOLLOW_UP, + UNFREEZE_REASON_OOM_ADJ_RECONFIGURATION, }) @Retention(RetentionPolicy.SOURCE) public @interface UnfreezeReason {} @@ -2451,8 +2459,8 @@ public class CachedAppOptimizer { synchronized (mAm.mPidsSelfLocked) { pr = mAm.mPidsSelfLocked.get(blocked); } - if (pr != null - && pr.mState.getCurAdj() < ProcessList.FREEZER_CUTOFF_ADJ) { + if (pr != null && pr.mState.getCurAdj() + < mAm.mConstants.FREEZER_CUTOFF_ADJ) { Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks " + pr.processName + " (" + blocked + ")"); // Found at least one blocked non-cached process @@ -2539,6 +2547,10 @@ public class CachedAppOptimizer { return UNFREEZE_REASON_RESTRICTION_CHANGE; case OOM_ADJ_REASON_COMPONENT_DISABLED: return UNFREEZE_REASON_COMPONENT_DISABLED; + case OOM_ADJ_REASON_FOLLOW_UP: + return UNFREEZE_REASON_OOM_ADJ_FOLLOW_UP; + case OOM_ADJ_REASON_RECONFIGURATION: + return UNFREEZE_REASON_OOM_ADJ_RECONFIGURATION; default: return UNFREEZE_REASON_NONE; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index aadf6f61956c..9c569db99797 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -55,6 +55,7 @@ import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; +import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RECONFIGURATION; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; @@ -105,7 +106,6 @@ import static com.android.server.am.ProcessList.CACHED_APP_IMPORTANCE_LEVELS; import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ; import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ; import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ; -import static com.android.server.am.ProcessList.FREEZER_CUTOFF_ADJ; import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ; import static com.android.server.am.ProcessList.HOME_APP_ADJ; import static com.android.server.am.ProcessList.INVALID_ADJ; @@ -232,6 +232,8 @@ public class OomAdjuster { return AppProtoEnums.OOM_ADJ_REASON_COMPONENT_DISABLED; case OOM_ADJ_REASON_FOLLOW_UP: return AppProtoEnums.OOM_ADJ_REASON_FOLLOW_UP; + case OOM_ADJ_REASON_RECONFIGURATION: + return AppProtoEnums.OOM_ADJ_REASON_RECONFIGURATION; default: return AppProtoEnums.OOM_ADJ_REASON_UNKNOWN_TO_PROTO; } @@ -288,6 +290,8 @@ public class OomAdjuster { return OOM_ADJ_REASON_METHOD + "_componentDisabled"; case OOM_ADJ_REASON_FOLLOW_UP: return OOM_ADJ_REASON_METHOD + "_followUp"; + case OOM_ADJ_REASON_RECONFIGURATION: + return OOM_ADJ_REASON_METHOD + "_reconfiguration"; default: return "_unknown"; } @@ -4079,7 +4083,7 @@ public class OomAdjuster { } // Reasons to freeze: - if (proc.mState.getCurAdj() >= FREEZER_CUTOFF_ADJ) { + if (proc.mState.getCurAdj() >= mConstants.FREEZER_CUTOFF_ADJ) { // Oomscore is in a high enough state, it is safe to freeze. return true; } @@ -4098,9 +4102,8 @@ public class OomAdjuster { final ProcessCachedOptimizerRecord opt = app.mOptRecord; final ProcessStateRecord state = app.mState; if (Flags.traceUpdateAppFreezeStateLsp()) { - final boolean oomAdjChanged = - (state.getCurAdj() >= FREEZER_CUTOFF_ADJ ^ oldOomAdj >= FREEZER_CUTOFF_ADJ) - || oldOomAdj == UNKNOWN_ADJ; + final boolean oomAdjChanged = (state.getCurAdj() >= mConstants.FREEZER_CUTOFF_ADJ + ^ oldOomAdj >= mConstants.FREEZER_CUTOFF_ADJ) || oldOomAdj == UNKNOWN_ADJ; final boolean shouldNotFreezeChanged = opt.shouldNotFreezeAdjSeq() == mAdjSeq; final boolean hasCpuCapability = (PROCESS_CAPABILITY_CPU_TIME & app.mState.getCurCapability()) diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java index 123780fb7567..99bdd10ff71b 100644 --- a/services/core/java/com/android/server/am/PhantomProcessList.java +++ b/services/core/java/com/android/server/am/PhantomProcessList.java @@ -112,23 +112,10 @@ public final class PhantomProcessList { private final ActivityManagerService mService; private final Handler mKillHandler; - private static final int CGROUP_V1 = 0; - private static final int CGROUP_V2 = 1; - private static final String[] CGROUP_PATH_PREFIXES = { - "/acct/uid_" /* cgroup v1 */, - "/sys/fs/cgroup/uid_" /* cgroup v2 */ - }; - private static final String CGROUP_PID_PREFIX = "/pid_"; - private static final String CGROUP_PROCS = "/cgroup.procs"; - - @VisibleForTesting - int mCgroupVersion = CGROUP_V1; - PhantomProcessList(final ActivityManagerService service) { mService = service; mKillHandler = service.mProcessList.sKillHandler; mInjector = new Injector(); - probeCgroupVersion(); } @VisibleForTesting @@ -157,9 +144,15 @@ public final class PhantomProcessList { final int appPid = app.getPid(); InputStream input = mCgroupProcsFds.get(appPid); if (input == null) { - final String path = getCgroupFilePath(app.info.uid, appPid); + String path = null; try { + path = getCgroupFilePath(app.info.uid, appPid); input = mInjector.openCgroupProcs(path); + } catch (IllegalArgumentException e) { + if (DEBUG_PROCESSES) { + Slog.w(TAG, "Unable to obtain cgroup.procs path ", e); + } + return; } catch (FileNotFoundException | SecurityException e) { if (DEBUG_PROCESSES) { Slog.w(TAG, "Unable to open " + path, e); @@ -207,18 +200,9 @@ public final class PhantomProcessList { } } - private void probeCgroupVersion() { - for (int i = CGROUP_PATH_PREFIXES.length - 1; i >= 0; i--) { - if ((new File(CGROUP_PATH_PREFIXES[i] + Process.SYSTEM_UID)).exists()) { - mCgroupVersion = i; - break; - } - } - } - @VisibleForTesting String getCgroupFilePath(int uid, int pid) { - return CGROUP_PATH_PREFIXES[mCgroupVersion] + uid + CGROUP_PID_PREFIX + pid + CGROUP_PROCS; + return nativeGetCgroupProcsPath(uid, pid); } static String getProcessName(int pid) { @@ -630,4 +614,7 @@ public final class PhantomProcessList { return PhantomProcessList.getProcessName(pid); } } + + private static native String nativeGetCgroupProcsPath(int uid, int pid) + throws IllegalArgumentException; } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 70febcd63455..bddde9d589f3 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -383,12 +383,6 @@ public final class ProcessList { private static final long LMKD_RECONNECT_DELAY_MS = 1000; /** - * The cuttoff adj for the freezer, app processes with adj greater than this value will be - * eligible for the freezer. - */ - static final int FREEZER_CUTOFF_ADJ = CACHED_APP_MIN_ADJ; - - /** * Apps have no access to the private data directories of any other app, even if the other * app has made them world-readable. */ diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 98f738c38d63..49149e1fa415 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1699,7 +1699,7 @@ class ProcessRecord implements WindowProcessListener { return mService.mOomAdjuster.mCachedAppOptimizer.useFreezer() && !mOptRecord.isFreezeExempt() && !mOptRecord.shouldNotFreeze() - && mState.getCurAdj() >= ProcessList.FREEZER_CUTOFF_ADJ; + && mState.getCurAdj() >= mService.mConstants.FREEZER_CUTOFF_ADJ; } public void forEachConnectionHost(Consumer<ProcessRecord> consumer) { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 87f87c76725e..c82933c5069e 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -158,6 +158,7 @@ public class SettingsToPropertiesMapper { "aoc", "app_widgets", "arc_next", + "art_cloud", "art_mainline", "art_performance", "attack_tools", diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c31b9ef60bd2..70f2a8e1dd1b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -160,6 +160,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -176,6 +177,9 @@ import java.util.function.Consumer; class UserController implements Handler.Callback { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM; + // Amount of time we wait for observers to handle onBeforeUserSwitching, before crashing system. + static final int DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS = 20 * 1000; + // Amount of time we wait for observers to handle a user switch before // giving up on them and dismissing the user switching dialog. static final int DEFAULT_USER_SWITCH_TIMEOUT_MS = 3 * 1000; @@ -1920,8 +1924,14 @@ class UserController implements Handler.Callback { return false; } - mHandler.post(() -> startUserInternalOnHandler(userId, oldUserId, userStartMode, - unlockListener, callingUid, callingPid)); + final Runnable continueStartUserInternal = () -> continueStartUserInternal(userInfo, + oldUserId, userStartMode, unlockListener, callingUid, callingPid); + if (foreground) { + mHandler.post(() -> dispatchOnBeforeUserSwitching(userId, () -> + mHandler.post(continueStartUserInternal))); + } else { + continueStartUserInternal.run(); + } } finally { Binder.restoreCallingIdentity(ident); } @@ -1929,11 +1939,11 @@ class UserController implements Handler.Callback { return true; } - private void startUserInternalOnHandler(int userId, int oldUserId, int userStartMode, + private void continueStartUserInternal(UserInfo userInfo, int oldUserId, int userStartMode, IProgressListener unlockListener, int callingUid, int callingPid) { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); final boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; - final UserInfo userInfo = getUserInfo(userId); + final int userId = userInfo.id; boolean needStart = false; boolean updateUmState = false; @@ -1995,7 +2005,6 @@ class UserController implements Handler.Callback { // it should be moved outside, but for now it's not as there are many calls to // external components here afterwards updateProfileRelatedCaches(); - dispatchOnBeforeUserSwitching(userId); mInjector.getWindowManager().setCurrentUser(userId); mInjector.reportCurWakefulnessUsageEvent(); // Once the internal notion of the active user has switched, we lock the device @@ -2296,25 +2305,40 @@ class UserController implements Handler.Callback { mUserSwitchObservers.finishBroadcast(); } - private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId) { + private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId, Runnable onComplete) { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("dispatchOnBeforeUserSwitching-" + newUserId); - final int observerCount = mUserSwitchObservers.beginBroadcast(); - for (int i = 0; i < observerCount; i++) { - final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); - t.traceBegin("onBeforeUserSwitching-" + name); + final AtomicBoolean isSuccessful = new AtomicBoolean(false); + startTimeoutForOnBeforeUserSwitching(isSuccessful); + informUserSwitchObservers((observer, callback) -> { try { - mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId); + observer.onBeforeUserSwitching(newUserId, callback); } catch (RemoteException e) { - // Ignore - } finally { - t.traceEnd(); + // ignore } - } - mUserSwitchObservers.finishBroadcast(); + }, () -> { + isSuccessful.set(true); + onComplete.run(); + }, "onBeforeUserSwitching"); t.traceEnd(); } + private void startTimeoutForOnBeforeUserSwitching(AtomicBoolean isSuccessful) { + mHandler.postDelayed(() -> { + if (isSuccessful.get()) { + return; + } + String unresponsiveObservers; + synchronized (mLock) { + unresponsiveObservers = String.join(", ", mCurWaitingUserSwitchCallbacks); + } + throw new RuntimeException("Timeout on dispatchOnBeforeUserSwitching. " + + "These UserSwitchObservers did not respond in " + + DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS + "ms: " + unresponsiveObservers + "."); + }, DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS); + } + + /** Called on handler thread */ @VisibleForTesting void dispatchUserSwitchComplete(@UserIdInt int oldUserId, @UserIdInt int newUserId) { @@ -2527,70 +2551,76 @@ class UserController implements Handler.Callback { t.traceBegin("dispatchUserSwitch-" + oldUserId + "-to-" + newUserId); EventLog.writeEvent(EventLogTags.UC_DISPATCH_USER_SWITCH, oldUserId, newUserId); + uss.switching = true; + informUserSwitchObservers((observer, callback) -> { + try { + observer.onUserSwitching(newUserId, callback); + } catch (RemoteException e) { + // ignore + } + }, () -> { + synchronized (mLock) { + sendContinueUserSwitchLU(uss, oldUserId, newUserId); + } + }, "onUserSwitching"); + t.traceEnd(); + } + void informUserSwitchObservers(BiConsumer<IUserSwitchObserver, IRemoteCallback> consumer, + final Runnable onComplete, String trace) { final int observerCount = mUserSwitchObservers.beginBroadcast(); - if (observerCount > 0) { - final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); + if (observerCount == 0) { + onComplete.run(); + mUserSwitchObservers.finishBroadcast(); + return; + } + final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); + synchronized (mLock) { + mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; + } + final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); + final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); + final long dispatchStartedTime = SystemClock.elapsedRealtime(); + for (int i = 0; i < observerCount; i++) { + final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); + // Prepend with unique prefix to guarantee that keys are unique + final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); synchronized (mLock) { - uss.switching = true; - mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; - } - final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); - final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); - final long dispatchStartedTime = SystemClock.elapsedRealtime(); - for (int i = 0; i < observerCount; i++) { - final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); - try { - // Prepend with unique prefix to guarantee that keys are unique - final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); + curWaitingUserSwitchCallbacks.add(name); + } + final IRemoteCallback callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + asyncTraceEnd(trace + "-" + name, 0); synchronized (mLock) { - curWaitingUserSwitchCallbacks.add(name); - } - final IRemoteCallback callback = new IRemoteCallback.Stub() { - @Override - public void sendResult(Bundle data) throws RemoteException { - asyncTraceEnd("onUserSwitching-" + name, newUserId); - synchronized (mLock) { - long delayForObserver = SystemClock.elapsedRealtime() - - dispatchStartedTimeForObserver; - if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { - Slogf.w(TAG, "User switch slowed down by observer " + name - + ": result took " + delayForObserver - + " ms to process."); - } - - long totalDelay = SystemClock.elapsedRealtime() - - dispatchStartedTime; - if (totalDelay > userSwitchTimeoutMs) { - Slogf.e(TAG, "User switch timeout: observer " + name - + "'s result was received " + totalDelay - + " ms after dispatchUserSwitch."); - } - - curWaitingUserSwitchCallbacks.remove(name); - // Continue switching if all callbacks have been notified and - // user switching session is still valid - if (waitingCallbacksCount.decrementAndGet() == 0 - && (curWaitingUserSwitchCallbacks - == mCurWaitingUserSwitchCallbacks)) { - sendContinueUserSwitchLU(uss, oldUserId, newUserId); - } - } + long delayForObserver = SystemClock.elapsedRealtime() + - dispatchStartedTimeForObserver; + if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { + Slogf.w(TAG, "User switch slowed down by observer " + name + + ": result took " + delayForObserver + + " ms to process. " + trace); } - }; - asyncTraceBegin("onUserSwitching-" + name, newUserId); - mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback); - } catch (RemoteException e) { - // Ignore + long totalDelay = SystemClock.elapsedRealtime() - dispatchStartedTime; + if (totalDelay > userSwitchTimeoutMs) { + Slogf.e(TAG, "User switch timeout: observer " + name + + "'s result was received " + totalDelay + + " ms after dispatchUserSwitch. " + trace); + } + curWaitingUserSwitchCallbacks.remove(name); + // Continue switching if all callbacks have been notified and + // user switching session is still valid + if (waitingCallbacksCount.decrementAndGet() == 0 + && (curWaitingUserSwitchCallbacks + == mCurWaitingUserSwitchCallbacks)) { + onComplete.run(); + } + } } - } - } else { - synchronized (mLock) { - sendContinueUserSwitchLU(uss, oldUserId, newUserId); - } + }; + asyncTraceBegin(trace + "-" + name, 0); + consumer.accept(mUserSwitchObservers.getBroadcastItem(i), callback); } mUserSwitchObservers.finishBroadcast(); - t.traceEnd(); // end dispatchUserSwitch- } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index 89e4a8d82676..cfcede8ee40d 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -288,3 +288,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "expedite_activity_launch_on_cold_start" + namespace: "system_performance" + description: "Notify ActivityTaskManager of cold starts early to fix app launch behavior." + bug: "319519089" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 06c586f5e9c2..295e0443371d 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3191,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub { resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted, - "proxy " + message, shouldCollectMessage); + "proxy " + message, shouldCollectMessage, 1); if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag, proxiedPackageName); @@ -3210,7 +3210,20 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName, proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp, - message, shouldCollectMessage); + message, shouldCollectMessage, 1); + } + + @Override + public void noteOperationsInBatch(Map batchedNoteOps) { + for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) { + AppOpsManager.NotedOp notedOp = entry.getKey(); + int notedCount = entry.getValue(); + mCheckOpsDelegateDispatcher.noteOperation( + notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(), + notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(), + notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(), + notedOp.getShouldCollectMessage(), notedCount); + } } @Override @@ -3228,7 +3241,7 @@ public class AppOpsService extends IAppOpsService.Stub { } return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message, - shouldCollectMessage); + shouldCollectMessage, 1); } @Override @@ -3237,13 +3250,12 @@ public class AppOpsService extends IAppOpsService.Stub { String message, boolean shouldCollectMessage) { return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage); + shouldCollectMessage, 1); } private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName, - @Nullable String attributionTag, int virtualDeviceId, - boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage) { + @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, + @Nullable String message, boolean shouldCollectMessage, int notedCount) { String resolvedPackageName; if (!shouldUseNewCheckOp()) { verifyIncomingUid(uid); @@ -3278,14 +3290,14 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag, virtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp, - message, shouldCollectMessage); + message, shouldCollectMessage, notedCount); } private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int virtualDeviceId, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage) { + boolean shouldCollectMessage, int notedCount) { PackageVerificationResult pvr; try { pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); @@ -3388,11 +3400,11 @@ public class AppOpsService extends IAppOpsService.Stub { virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED); attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, - getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags); + getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount); if (shouldCollectAsyncNotedOp) { collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message, - shouldCollectMessage); + shouldCollectMessage, notedCount); } return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag, @@ -3551,7 +3563,7 @@ public class AppOpsService extends IAppOpsService.Stub { */ private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, - boolean shouldCollectMessage) { + boolean shouldCollectMessage, int notedCount) { Objects.requireNonNull(message); int callingUid = Binder.getCallingUid(); @@ -3559,42 +3571,51 @@ public class AppOpsService extends IAppOpsService.Stub { final long token = Binder.clearCallingIdentity(); try { synchronized (this) { - Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); - - RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); - AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, - attributionTag, message, System.currentTimeMillis()); - final boolean[] wasNoteForwarded = {false}; - if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0 && shouldCollectMessage) { reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag, message); } - if (callbacks != null) { + Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); + RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); + if (callbacks == null) { + return; + } + + final boolean[] wasNoteForwarded = {false}; + if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) { + notedCount = 1; + } + + for (int i = 0; i < notedCount; i++) { + AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, + attributionTag, message, System.currentTimeMillis()); + wasNoteForwarded[0] = false; callbacks.broadcast((cb) -> { try { cb.opNoted(asyncNotedOp); wasNoteForwarded[0] = true; } catch (RemoteException e) { Slog.e(TAG, - "Could not forward noteOp of " + opCode + " to " + packageName + "Could not forward noteOp of " + opCode + " to " + + packageName + "/" + uid + "(" + attributionTag + ")", e); } }); - } - if (!wasNoteForwarded[0]) { - ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key); - if (unforwardedOps == null) { - unforwardedOps = new ArrayList<>(1); - mUnforwardedAsyncNotedOps.put(key, unforwardedOps); - } + if (!wasNoteForwarded[0]) { + ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get( + key); + if (unforwardedOps == null) { + unforwardedOps = new ArrayList<>(1); + mUnforwardedAsyncNotedOps.put(key, unforwardedOps); + } - unforwardedOps.add(asyncNotedOp); - if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { - unforwardedOps.remove(0); + unforwardedOps.add(asyncNotedOp); + if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { + unforwardedOps.remove(0); + } } } } @@ -4026,7 +4047,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (shouldCollectAsyncNotedOp && !isRestricted) { collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF, - message, shouldCollectMessage); + message, shouldCollectMessage, 1); } return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag, @@ -7574,34 +7595,36 @@ public class AppOpsService extends IAppOpsService.Stub { public SyncNotedAppOp noteOperation(int code, int uid, String packageName, String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - String message, boolean shouldCollectMessage) { + String message, boolean shouldCollectMessage, int notedCount) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, this::noteDelegateOperationImpl + shouldCollectMessage, notedCount, this::noteDelegateOperationImpl ); } else { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, AppOpsService.this::noteOperationImpl + shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl ); } } else if (mCheckOpsDelegate != null) { return noteDelegateOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, + notedCount); } return noteOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, + notedCount); } private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage) { + boolean shouldCollectMessage, int notedCount) { return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId, virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - AppOpsService.this::noteOperationImpl + notedCount, AppOpsService.this::noteOperationImpl ); } diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index 314664b0a79d..4d114b4ad4ac 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -100,10 +100,12 @@ final class AttributedOp { * @param proxyDeviceId The device Id of the proxy * @param uidState UID state of the app noteOp/startOp was called for * @param flags OpFlags of the call + * @param accessCount The number of times the op is accessed */ public void accessed(int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId, - @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) { + @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags, + int accessCount) { long accessTime = System.currentTimeMillis(); accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId, uidState, flags); @@ -111,7 +113,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE, - DiscreteRegistry.ACCESS_TYPE_NOTE_OP); + DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount); } /** @@ -255,7 +257,7 @@ final class AttributedOp { if (isStarted) { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, startTime, - attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP); + attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1); } } @@ -451,7 +453,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, event.getUidState(), event.getFlags(), startTime, event.getAttributionFlags(), - event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP); + event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1); if (shouldSendActive) { mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, tag, event.getVirtualDeviceId(), true, diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 6b0253864e2b..5e67f26ba1f6 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -475,7 +475,7 @@ final class HistoricalRegistry { @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags, long accessTime, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId, - @DiscreteRegistry.AccessType int accessType) { + @DiscreteRegistry.AccessType int accessType, int accessCount) { synchronized (mInMemoryLock) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (!isPersistenceInitializedMLocked()) { @@ -484,7 +484,7 @@ final class HistoricalRegistry { } getUpdatedPendingHistoricalOpsMLocked( System.currentTimeMillis()).increaseAccessCount(op, uid, packageName, - attributionTag, uidState, flags, 1); + attributionTag, uidState, flags, accessCount); mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags, uidState, accessTime, -1, attributionFlags, diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java index 4d5bce559a91..fedfe511b747 100644 --- a/services/core/java/com/android/server/audio/FadeOutManager.java +++ b/services/core/java/com/android/server/audio/FadeOutManager.java @@ -199,7 +199,9 @@ public final class FadeOutManager { for (AudioPlaybackConfiguration apc : players) { final VolumeShaper.Configuration volShaper = mFadeConfigurations.getFadeOutVolumeShaperConfig(apc.getAudioAttributes()); - fa.addFade(apc, /* skipRamp= */ false, volShaper); + if (volShaper != null) { + fa.addFade(apc, /* skipRamp= */ false, volShaper); + } } } } @@ -249,7 +251,7 @@ public final class FadeOutManager { final VolumeShaper.Configuration volShaper = mFadeConfigurations.getFadeOutVolumeShaperConfig(apc.getAudioAttributes()); final FadedOutApp fa = mUidToFadedAppsMap.get(apc.getClientUid()); - if (fa == null) { + if (fa == null || volShaper == null) { return; } fa.addFade(apc, /* skipRamp= */ true, volShaper); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index bad5b8b9567a..f145a47eb935 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -21,8 +21,11 @@ import static android.Manifest.permission.ADD_MIRROR_DISPLAY; import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT; import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT; +import static android.Manifest.permission.CONFIGURE_WIFI_DISPLAY; +import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.MANAGE_DISPLAYS; +import static android.Manifest.permission.MODIFY_HDR_CONVERSION_MODE; import static android.Manifest.permission.RESTRICT_DISPLAY_MODES; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; @@ -119,6 +122,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.IBinder.DeathRecipient; +import android.os.IBinder.FrozenStateChangeCallback; import android.os.IThermalService; import android.os.Looper; import android.os.Message; @@ -272,6 +276,7 @@ public final class DisplayManagerService extends SystemService { private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7; private static final int MSG_DELIVER_DISPLAY_GROUP_EVENT = 8; private static final int MSG_RECEIVED_DEVICE_STATE = 9; + private static final int MSG_DISPATCH_PENDING_PROCESS_EVENTS = 10; private static final int[] EMPTY_ARRAY = new int[0]; private static final HdrConversionMode HDR_CONVERSION_MODE_UNSUPPORTED = new HdrConversionMode( HDR_CONVERSION_UNSUPPORTED); @@ -286,7 +291,6 @@ public final class DisplayManagerService extends SystemService { private InputManagerInternal mInputManagerInternal; private ActivityManagerInternal mActivityManagerInternal; private final UidImportanceListener mUidImportanceListener = new UidImportanceListener(); - private final DisplayFrozenProcessListener mDisplayFrozenProcessListener; @Nullable private IMediaProjectionManager mProjectionService; @@ -630,7 +634,6 @@ public final class DisplayManagerService extends SystemService { mFlags = injector.getFlags(); mHandler = new DisplayManagerHandler(displayThreadLooper); mHandlerExecutor = new HandlerExecutor(mHandler); - mDisplayFrozenProcessListener = new DisplayFrozenProcessListener(); mUiHandler = UiThread.getHandler(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore); mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, @@ -1165,31 +1168,11 @@ public final class DisplayManagerService extends SystemService { } } - private class DisplayFrozenProcessListener - implements ActivityManagerInternal.FrozenProcessListener { - public void onProcessFrozen(int pid) { - synchronized (mSyncRoot) { - CallbackRecord callback = mCallbacks.get(pid); - if (callback == null) { - return; - } - callback.setFrozen(true); - } - } - - public void onProcessUnfrozen(int pid) { - // First, see if there is a callback associated with this pid. If there's no - // callback, then there is nothing to do. - CallbackRecord callback; - synchronized (mSyncRoot) { - callback = mCallbacks.get(pid); - if (callback == null) { - return; - } - callback.setFrozen(false); - } - // Attempt to dispatch pending events if the process is coming out of frozen. + private void dispatchPendingProcessEvents(@NonNull Object cb) { + if (cb instanceof CallbackRecord callback) { callback.dispatchPending(); + } else { + Slog.wtf(TAG, "not a callback: " + cb); } } @@ -2397,9 +2380,13 @@ public final class DisplayManagerService extends SystemService { // We don't bother invalidating the display info caches here because any changes to the // display info will trigger a cache invalidation inside of LogicalDisplay before we hit // this point. - sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); applyDisplayChangedLocked(display); + + if (mDisplayTopologyCoordinator != null) { + mDisplayTopologyCoordinator.onDisplayChanged(display.getDisplayInfoLocked()); + } } private void applyDisplayChangedLocked(@NonNull LogicalDisplay display) { @@ -2643,7 +2630,8 @@ public final class DisplayManagerService extends SystemService { private void updateCanHostTasksIfNeededLocked(LogicalDisplay display) { if (display.setCanHostTasksLocked(!mMirrorBuiltInDisplay)) { - sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + sendDisplayEventIfEnabledLocked(display, + DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); } } @@ -3474,7 +3462,7 @@ public final class DisplayManagerService extends SystemService { private void sendDisplayEventFrameRateOverrideLocked(int displayId) { Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE, - displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); + displayId, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); mHandler.sendMessage(msg); } @@ -4047,6 +4035,9 @@ public final class DisplayManagerService extends SystemService { deliverDisplayGroupEvent(msg.arg1, msg.arg2); break; + case MSG_DISPATCH_PENDING_PROCESS_EVENTS: + dispatchPendingProcessEvents(msg.obj); + break; } } } @@ -4061,7 +4052,7 @@ public final class DisplayManagerService extends SystemService { handleLogicalDisplayAddedLocked(display); break; - case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED: + case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_BASIC_CHANGED: handleLogicalDisplayChangedLocked(display); break; @@ -4114,7 +4105,7 @@ public final class DisplayManagerService extends SystemService { } } - private final class CallbackRecord implements DeathRecipient { + private final class CallbackRecord implements DeathRecipient, FrozenStateChangeCallback { public final int mPid; public final int mUid; private final IDisplayManagerCallback mCallback; @@ -4137,6 +4128,8 @@ public final class DisplayManagerService extends SystemService { private boolean mCached; @GuardedBy("mCallback") private boolean mFrozen; + @GuardedBy("mCallback") + private boolean mAlive; CallbackRecord(int pid, int uid, @NonNull IDisplayManagerCallback callback, @InternalEventFlag long internalEventFlagsMask) { @@ -4146,18 +4139,20 @@ public final class DisplayManagerService extends SystemService { mInternalEventFlagsMask = new AtomicLong(internalEventFlagsMask); mCached = false; mFrozen = false; + mAlive = true; if (deferDisplayEventsWhenFrozen()) { - // Some CallbackRecords are registered very early in system boot, before - // mActivityManagerInternal is initialized. If mActivityManagerInternal is null, - // do not register the frozen process listener. However, do verify that all such - // registrations are for the self pid (which can never be frozen, so the frozen - // process listener does not matter). - if (mActivityManagerInternal != null) { - mActivityManagerInternal.addFrozenProcessListener(pid, mHandlerExecutor, - mDisplayFrozenProcessListener); - } else if (Process.myPid() != pid) { - Slog.e(TAG, "DisplayListener registered too early"); + try { + callback.asBinder().addFrozenStateChangeCallback(this); + } catch (UnsupportedOperationException e) { + // Ignore the exception. The callback is not supported on this platform or on + // this binder. The callback is never supported for local binders. There is + // no error: the UID importance listener will still operate. A log message is + // provided for debug. + Slog.v(TAG, "FrozenStateChangeCallback not supported for pid " + mPid); + } catch (RemoteException e) { + // This is unexpected. Just give up. + throw new RuntimeException(e); } } @@ -4182,7 +4177,7 @@ public final class DisplayManagerService extends SystemService { */ @GuardedBy("mCallback") private boolean hasPendingAndIsReadyLocked() { - return isReadyLocked() && mPendingEvents != null && !mPendingEvents.isEmpty(); + return isReadyLocked() && mPendingEvents != null && !mPendingEvents.isEmpty() && mAlive; } /** @@ -4190,7 +4185,7 @@ public final class DisplayManagerService extends SystemService { * receive events and there are pending events to be delivered. * This is only used if {@link deferDisplayEventsWhenFrozen()} is true. */ - public boolean setFrozen(boolean frozen) { + private boolean setFrozen(boolean frozen) { synchronized (mCallback) { mFrozen = frozen; return hasPendingAndIsReadyLocked(); @@ -4211,6 +4206,9 @@ public final class DisplayManagerService extends SystemService { @Override public void binderDied() { + synchronized (mCallback) { + mAlive = false; + } if (DEBUG || extraLogging(mPackageName)) { Slog.d(TAG, "Display listener for pid " + mPid + " died."); } @@ -4221,6 +4219,14 @@ public final class DisplayManagerService extends SystemService { onCallbackDied(this); } + @Override + public void onFrozenStateChanged(@NonNull IBinder who, int state) { + if (setFrozen(state == FrozenStateChangeCallback.STATE_FROZEN)) { + Message msg = mHandler.obtainMessage(MSG_DISPATCH_PENDING_PROCESS_EVENTS, this); + mHandler.sendMessage(msg); + } + } + /** * @return {@code false} if RemoteException happens; otherwise {@code true} for * success. This returns true even if the event was deferred because the remote client is @@ -4286,8 +4292,9 @@ public final class DisplayManagerService extends SystemService { switch (event) { case DisplayManagerGlobal.EVENT_DISPLAY_ADDED: return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED) != 0; - case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED: - return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED) != 0; + case DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED: + return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED) + != 0; case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED: return (mask & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED) @@ -4386,7 +4393,7 @@ public final class DisplayManagerService extends SystemService { // This is only used if {@link deferDisplayEventsWhenFrozen()} is true. public boolean dispatchPending() { synchronized (mCallback) { - if (mPendingEvents == null || mPendingEvents.isEmpty()) { + if (mPendingEvents == null || mPendingEvents.isEmpty() || !mAlive) { return true; } if (!isReadyLocked()) { @@ -4542,7 +4549,8 @@ public final class DisplayManagerService extends SystemService { public void registerCallback(IDisplayManagerCallback callback) { registerCallbackWithEventMask(callback, DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED); } @@ -4602,13 +4610,13 @@ public final class DisplayManagerService extends SystemService { } } + @EnforcePermission(CONFIGURE_WIFI_DISPLAY) @Override // Binder call public void connectWifiDisplay(String address) { + connectWifiDisplay_enforcePermission(); if (address == null) { throw new IllegalArgumentException("address must not be null"); } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to connect to a wifi display"); final long token = Binder.clearCallingIdentity(); try { @@ -4633,13 +4641,13 @@ public final class DisplayManagerService extends SystemService { } } + @EnforcePermission(CONFIGURE_WIFI_DISPLAY) @Override // Binder call public void renameWifiDisplay(String address, String alias) { + renameWifiDisplay_enforcePermission(); if (address == null) { throw new IllegalArgumentException("address must not be null"); } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to rename to a wifi display"); final long token = Binder.clearCallingIdentity(); try { @@ -4649,13 +4657,13 @@ public final class DisplayManagerService extends SystemService { } } + @EnforcePermission(CONFIGURE_WIFI_DISPLAY) @Override // Binder call public void forgetWifiDisplay(String address) { + forgetWifiDisplay_enforcePermission(); if (address == null) { throw new IllegalArgumentException("address must not be null"); } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to forget to a wifi display"); final long token = Binder.clearCallingIdentity(); try { @@ -4999,7 +5007,7 @@ public final class DisplayManagerService extends SystemService { } } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override public BrightnessInfo getBrightnessInfo(int displayId) { getBrightnessInfo_enforcePermission(); @@ -5030,7 +5038,7 @@ public final class DisplayManagerService extends SystemService { } } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public void setTemporaryBrightness(int displayId, float brightness) { setTemporaryBrightness_enforcePermission(); @@ -5045,7 +5053,7 @@ public final class DisplayManagerService extends SystemService { } } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public void setBrightness(int displayId, float brightness) { setBrightness_enforcePermission(); @@ -5069,12 +5077,11 @@ public final class DisplayManagerService extends SystemService { } } + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public float getBrightness(int displayId) { + getBrightness_enforcePermission(); float brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mContext.enforceCallingOrSelfPermission( - Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS, - "Permission required to set the display's brightness"); final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { @@ -5089,7 +5096,7 @@ public final class DisplayManagerService extends SystemService { return brightness; } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public void setTemporaryAutoBrightnessAdjustment(float adjustment) { setTemporaryAutoBrightnessAdjustment_enforcePermission(); @@ -5164,14 +5171,13 @@ public final class DisplayManagerService extends SystemService { } } + @EnforcePermission(MODIFY_HDR_CONVERSION_MODE) @Override // Binder call public void setHdrConversionMode(HdrConversionMode hdrConversionMode) { + setHdrConversionMode_enforcePermission(); if (!mIsHdrOutputControlEnabled) { return; } - mContext.enforceCallingOrSelfPermission( - Manifest.permission.MODIFY_HDR_CONVERSION_MODE, - "Permission required to set the HDR conversion mode."); final long token = Binder.clearCallingIdentity(); try { setHdrConversionModeInternal(hdrConversionMode); @@ -5335,7 +5341,7 @@ public final class DisplayManagerService extends SystemService { ? ddc.getHdrBrightnessData().highestHdrSdrRatio : 1; } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public float[] getDozeBrightnessSensorValueToBrightness(int displayId) { getDozeBrightnessSensorValueToBrightness_enforcePermission(); @@ -5348,7 +5354,7 @@ public final class DisplayManagerService extends SystemService { return ddc.getDozeBrightnessSensorValueToBrightness(); } - @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) + @EnforcePermission(CONTROL_DISPLAY_BRIGHTNESS) @Override // Binder call public float getDefaultDozeBrightness(int displayId) { getDefaultDozeBrightness_enforcePermission(); @@ -6057,6 +6063,7 @@ public final class DisplayManagerService extends SystemService { * Return the value of the pause */ private static boolean deferDisplayEventsWhenFrozen() { - return com.android.server.am.Flags.deferDisplayEventsWhenFrozen(); + return android.os.Flags.binderFrozenStateChangeCallback() + && com.android.server.am.Flags.deferDisplayEventsWhenFrozen(); } } diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java index 5b78726cc421..461a9f3f2a0d 100644 --- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java +++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java @@ -85,13 +85,26 @@ class DisplayTopologyCoordinator { } /** + * Update the topology with display changes. + * @param info The new display info + */ + void onDisplayChanged(DisplayInfo info) { + synchronized (mSyncRoot) { + if (mTopology.updateDisplay(info.displayId, getWidth(info), getHeight(info))) { + sendTopologyUpdateLocked(); + } + } + } + + /** * Remove a display from the topology. * @param displayId The logical display ID */ void onDisplayRemoved(int displayId) { synchronized (mSyncRoot) { - mTopology.removeDisplay(displayId); - sendTopologyUpdateLocked(); + if (mTopology.removeDisplay(displayId)) { + sendTopologyUpdateLocked(); + } } } diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 79592a656409..006921572977 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -81,7 +81,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { public static final int LOGICAL_DISPLAY_EVENT_BASE = 0; public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1 << 0; - public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 1 << 1; + public static final int LOGICAL_DISPLAY_EVENT_BASIC_CHANGED = 1 << 1; public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 1 << 2; public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 1 << 3; public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 1 << 4; @@ -172,9 +172,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { /** * Has an entry for every logical display that the rest of the system has been notified about. - * Any entry in here requires us to send a {@link LOGICAL_DISPLAY_EVENT_REMOVED} event when it - * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. The values are any - * of the {@code UPDATE_STATE_*} constant types. + * The values are any of the {@code UPDATE_STATE_*} constant types. */ private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray(); @@ -811,7 +809,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final boolean isCurrentlyEnabled = display.isEnabledLocked(); int logicalDisplayEventMask = mLogicalDisplaysToUpdate .get(displayId, LOGICAL_DISPLAY_EVENT_BASE); - + boolean hasBasicInfoChanged = + !mTempDisplayInfo.equals(newDisplayInfo, /* compareRefreshRate */ false); // The display is no longer valid and needs to be removed. if (!display.isValidLocked()) { // Remove from group @@ -863,19 +862,28 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED : LOGICAL_DISPLAY_EVENT_REMOVED; logicalDisplayEventMask |= event; - } else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) { + } else if (wasDirty) { // If only the hdr/sdr ratio changed, then send just the event for that case if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED; } else { - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED; + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED + | LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED + | LOGICAL_DISPLAY_EVENT_STATE_CHANGED; } + } else if (hasBasicInfoChanged + || mTempDisplayInfo.getRefreshRate() != newDisplayInfo.getRefreshRate()) { + // If only the hdr/sdr ratio changed, then send just the event for that case + if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED; + } else { - if (mFlags.isDisplayListenerPerformanceImprovementsEnabled()) { + if (hasBasicInfoChanged) { + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED; + } logicalDisplayEventMask |= updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo); } - // The display is involved in a display layout transition } else if (updateState == UPDATE_STATE_TRANSITION) { logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION; @@ -891,7 +899,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // things like display cutouts. display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo); if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) { - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED; + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED + | LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; } } mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask); @@ -930,7 +939,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (mFlags.isConnectedDisplayManagementEnabled()) { sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); } - sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED); + sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_BASIC_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); @@ -962,7 +971,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mask |= LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; } - if (mTempDisplayInfo.state != newDisplayInfo.state) { + if (mFlags.isDisplayListenerPerformanceImprovementsEnabled() + && mTempDisplayInfo.state != newDisplayInfo.state) { mask |= LOGICAL_DISPLAY_EVENT_STATE_CHANGED; } return mask; @@ -1357,8 +1367,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return "added"; case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: return "transition"; - case LOGICAL_DISPLAY_EVENT_CHANGED: - return "changed"; case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: return "framerate_override"; case LOGICAL_DISPLAY_EVENT_SWAPPED: @@ -1375,6 +1383,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return "state_changed"; case LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED: return "refresh_rate_changed"; + case LOGICAL_DISPLAY_EVENT_BASIC_CHANGED: + return "basic_changed"; } return null; } 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 3358f723709c..5f974104f86b 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 @@ -96,7 +96,7 @@ flag { name: "display_topology" namespace: "display_manager" description: "Display topology for moving cursors and windows between extended displays" - bug: "278199220" + bug: "364906028" is_fixed_read_only: true } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 477660daa1de..4f3aa065b89b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -492,8 +492,8 @@ final class InputMethodBindingController { } if (getCurToken() != null) { - removeCurrentToken(); mService.resetSystemUiLocked(this); + removeCurrentToken(); mAutofillController.onResetSystemUi(); } diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyGnssAssistanceProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyGnssAssistanceProvider.java new file mode 100644 index 000000000000..6cab60c05b8e --- /dev/null +++ b/services/core/java/com/android/server/location/provider/proxy/ProxyGnssAssistanceProvider.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.provider.proxy; + +import android.annotation.Nullable; +import android.content.Context; +import android.location.provider.GnssAssistanceProviderBase; +import android.location.provider.IGnssAssistanceCallback; +import android.location.provider.IGnssAssistanceProvider; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.server.servicewatcher.CurrentUserServiceSupplier; +import com.android.server.servicewatcher.ServiceWatcher; + +/** + * Proxy for IGnssAssitanceProvider implementations. + */ +public class ProxyGnssAssistanceProvider { + + private static final String TAG = "GnssAssistanceProxy"; + /** + * Creates and registers this proxy. If no suitable service is available for the proxy, returns + * null. + */ + @Nullable + public static ProxyGnssAssistanceProvider createAndRegister(Context context) { + ProxyGnssAssistanceProvider proxy = new ProxyGnssAssistanceProvider(context); + if (proxy.register()) { + return proxy; + } else { + return null; + } + } + + private final ServiceWatcher mServiceWatcher; + + private ProxyGnssAssistanceProvider(Context context) { + mServiceWatcher = + ServiceWatcher.create( + context, + TAG, + CurrentUserServiceSupplier.createFromConfig( + context, + GnssAssistanceProviderBase.ACTION_GNSS_ASSISTANCE_PROVIDER, + com.android.internal.R.bool.config_enableGnssAssistanceOverlay, + com.android.internal.R.string + .config_gnssAssistanceProviderPackageName), + /* serviceListener= */ null); + } + + private boolean register() { + boolean resolves = mServiceWatcher.checkServiceResolves(); + if (resolves) { + mServiceWatcher.register(); + } + return resolves; + } + + /** + * Request GNSS assistance. + */ + public void request(IGnssAssistanceCallback callback) { + mServiceWatcher.runOnBinder( + new ServiceWatcher.BinderOperation() { + @Override + public void run(IBinder binder) throws RemoteException { + IGnssAssistanceProvider.Stub.asInterface(binder).request(callback); + } + + @Override + public void onError(Throwable t) { + try { + Log.w(TAG, "Error on requesting GnssAssistance: " + t); + callback.onError(); + } catch (RemoteException e) { + // ignore + } + } + }); + } +} diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 58c8450d714d..0d6e502cf965 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; +import android.media.MediaRoute2ProviderService.Reason; import android.media.MediaRouter2; import android.media.MediaRouter2Utils; import android.media.RouteDiscoveryPreference; @@ -123,6 +124,13 @@ abstract class MediaRoute2Provider { } } + /** Calls {@link Callback#onRequestFailed} with the given id and reason. */ + protected void notifyRequestFailed(long requestId, @Reason int reason) { + if (mCallback != null) { + mCallback.onRequestFailed(/* provider= */ this, requestId, reason); + } + } + void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo) { setProviderState(providerInfo); notifyProviderState(); @@ -171,11 +179,34 @@ abstract class MediaRoute2Provider { void onProviderStateChanged(@Nullable MediaRoute2Provider provider); void onSessionCreated(@NonNull MediaRoute2Provider provider, long requestId, @Nullable RoutingSessionInfo sessionInfo); - void onSessionUpdated(@NonNull MediaRoute2Provider provider, - @NonNull RoutingSessionInfo sessionInfo); + + /** + * Called when there's a session info change. + * + * <p>If the provided {@code sessionInfo} has a null {@link + * RoutingSessionInfo#getClientPackageName()}, that means that it's applicable to all + * packages. We call this type of routing session "global". This is typically used for + * system provided {@link RoutingSessionInfo}. However, some applications may be exempted + * from the global routing sessions, because their media is being routed using a session + * different from the global routing session. + * + * @param provider The provider that owns the session that changed. + * @param sessionInfo The new {@link RoutingSessionInfo}. + * @param packageNamesWithRoutingSessionOverrides The names of packages that are not + * affected by global session changes. This set may only be non-empty when the {@code + * sessionInfo} is for the global session, and therefore has no {@link + * RoutingSessionInfo#getClientPackageName()}. + */ + void onSessionUpdated( + @NonNull MediaRoute2Provider provider, + @NonNull RoutingSessionInfo sessionInfo, + Set<String> packageNamesWithRoutingSessionOverrides); + void onSessionReleased(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo); - void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId, int reason); + + void onRequestFailed( + @NonNull MediaRoute2Provider provider, long requestId, @Reason int reason); } /** diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index f09be2c15ee0..d6f7d3bdd4a4 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -16,6 +16,7 @@ package com.android.server.media; +import static android.media.MediaRoute2ProviderService.REASON_REJECTED; import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -31,6 +32,7 @@ import android.media.IMediaRoute2ProviderServiceCallback; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.media.MediaRoute2ProviderService; +import android.media.MediaRoute2ProviderService.Reason; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.os.Bundle; @@ -41,6 +43,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; import android.util.Slog; @@ -89,6 +92,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { mRequestIdToSessionCreationRequest; @GuardedBy("mLock") + private final Map<String, SystemMediaSessionCallback> mSystemSessionCallbacks; + + @GuardedBy("mLock") + private final LongSparseArray<SystemMediaSessionCallback> mRequestIdToSystemSessionRequest; + + @GuardedBy("mLock") private final Map<String, SessionCreationOrTransferRequest> mSessionOriginalIdToTransferRequest; MediaRoute2ProviderServiceProxy( @@ -102,6 +111,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { mContext = Objects.requireNonNull(context, "Context must not be null."); mRequestIdToSessionCreationRequest = new LongSparseArray<>(); mSessionOriginalIdToTransferRequest = new HashMap<>(); + mRequestIdToSystemSessionRequest = new LongSparseArray<>(); + mSystemSessionCallbacks = new ArrayMap<>(); mIsSelfScanOnlyProvider = isSelfScanOnlyProvider; mSupportsSystemMediaRouting = supportsSystemMediaRouting; mUserId = userId; @@ -236,6 +247,48 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { } } + /** + * Requests the creation of a system media routing session. + * + * @param requestId The id of the request. + * @param uid The uid of the package whose media to route, or {@link + * android.os.Process#INVALID_UID} if not applicable (for example, if all the system's media + * must be routed). + * @param packageName The package name to populate {@link + * RoutingSessionInfo#getClientPackageName()}. + * @param routeId The id of the route to be initially {@link + * RoutingSessionInfo#getSelectedRoutes()}. + * @param sessionHints An optional bundle with paramets. + * @param callback A {@link SystemMediaSessionCallback} to notify of session events. + * @see MediaRoute2ProviderService#onCreateSystemRoutingSession + */ + public void requestCreateSystemMediaSession( + long requestId, + int uid, + String packageName, + String routeId, + @Nullable Bundle sessionHints, + @NonNull SystemMediaSessionCallback callback) { + if (!Flags.enableMirroringInMediaRouter2()) { + throw new IllegalStateException( + "Unexpected call to requestCreateSystemMediaSession. Governing flag is" + + " disabled."); + } + if (mConnectionReady) { + boolean binderRequestSucceeded = + mActiveConnection.requestCreateSystemMediaSession( + requestId, uid, packageName, routeId, sessionHints); + if (!binderRequestSucceeded) { + // notify failure. + return; + } + updateBinding(); + synchronized (mLock) { + mRequestIdToSystemSessionRequest.put(requestId, callback); + } + } + } + public boolean hasComponentName(String packageName, String className) { return mComponentName.getPackageName().equals(packageName) && mComponentName.getClassName().equals(className); @@ -292,7 +345,14 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { mLastDiscoveryPreference != null && mLastDiscoveryPreference.shouldPerformActiveScan() && mSupportsSystemMediaRouting; + boolean bindDueToOngoingSystemMediaRoutingSessions = false; + if (Flags.enableMirroringInMediaRouter2()) { + synchronized (mLock) { + bindDueToOngoingSystemMediaRoutingSessions = !mSystemSessionCallbacks.isEmpty(); + } + } if (!getSessionInfos().isEmpty() + || bindDueToOngoingSystemMediaRoutingSessions || bindDueToManagerScan || bindDueToSystemMediaRoutingSupport) { return true; @@ -438,6 +498,14 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { String newSessionId = newSession.getId(); synchronized (mLock) { + var systemMediaSessionCallback = mRequestIdToSystemSessionRequest.get(requestId); + if (systemMediaSessionCallback != null) { + mRequestIdToSystemSessionRequest.remove(requestId); + mSystemSessionCallbacks.put(newSession.getOriginalId(), systemMediaSessionCallback); + systemMediaSessionCallback.onSessionUpdate(newSession); + return; + } + if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { newSession = createSessionWithPopulatedTransferInitiationDataLocked( @@ -569,6 +637,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { boolean found = false; synchronized (mLock) { + var sessionCallback = mSystemSessionCallbacks.get(releasedSession.getOriginalId()); + if (sessionCallback != null) { + sessionCallback.onSessionReleased(); + return; + } + mSessionOriginalIdToTransferRequest.remove(releasedSession.getId()); for (RoutingSessionInfo session : mSessionInfos) { if (TextUtils.equals(session.getId(), releasedSession.getId())) { @@ -602,7 +676,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { private void dispatchSessionUpdated(RoutingSessionInfo session) { mHandler.sendMessage( - obtainMessage(mCallback::onSessionUpdated, this, session)); + obtainMessage( + mCallback::onSessionUpdated, + this, + session, + /* packageNamesWithRoutingSessionOverrides= */ Set.of())); } private void dispatchSessionReleased(RoutingSessionInfo session) { @@ -645,6 +723,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { for (RoutingSessionInfo sessionInfo : mSessionInfos) { mCallback.onSessionReleased(this, sessionInfo); } + if (Flags.enableMirroringInMediaRouter2()) { + for (var callback : mSystemSessionCallbacks.values()) { + callback.onSessionReleased(); + } + mSystemSessionCallbacks.clear(); + int requestsSize = mRequestIdToSystemSessionRequest.size(); + for (int i = 0; i < requestsSize; i++) { + var callback = mRequestIdToSystemSessionRequest.valueAt(i); + var requestId = mRequestIdToSystemSessionRequest.keyAt(i); + callback.onRequestFailed(requestId, REASON_REJECTED); + } + mSystemSessionCallbacks.clear(); + } mSessionInfos.clear(); mReleasingSessions.clear(); mRequestIdToSessionCreationRequest.clear(); @@ -673,6 +764,26 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { pendingTransferCount); } + /** + * Callback for events related to system media sessions. + * + * @see MediaRoute2ProviderService#onCreateSystemRoutingSession + */ + public interface SystemMediaSessionCallback { + + /** + * Called when the corresponding session's {@link RoutingSessionInfo}, or upon the creation + * of the given session info. + */ + void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo); + + /** Called when the request with the given id fails for the given reason. */ + void onRequestFailed(long requestId, @Reason int reason); + + /** Called when the corresponding session is released. */ + void onSessionReleased(); + } + // All methods in this class are called on the main thread. private final class ServiceConnectionImpl implements ServiceConnection { @@ -739,6 +850,28 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { } } + /** + * Sends a system media session creation request to the provider service, and returns + * whether the request transaction succeeded. + * + * <p>The transaction might fail, for example, if the recipient process has died. + */ + public boolean requestCreateSystemMediaSession( + long requestId, + int uid, + String packageName, + String routeId, + @Nullable Bundle sessionHints) { + try { + mService.requestCreateSystemMediaSession( + requestId, uid, packageName, routeId, sessionHints); + return true; + } catch (RemoteException ex) { + Slog.e(TAG, "requestCreateSystemMediaSession: Failed to deliver request."); + } + return false; + } + public void releaseSession(long requestId, String sessionId) { try { mService.releaseSession(requestId, sessionId); diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 58deffcbd4ba..5e6737a485af 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -846,33 +846,29 @@ class MediaRouter2ServiceImpl { try { synchronized (mLock) { UserRecord userRecord = getOrCreateUserRecordLocked(userId); - List<RoutingSessionInfo> sessionInfos; + SystemMediaRoute2Provider systemProvider = userRecord.mHandler.getSystemProvider(); if (hasSystemRoutingPermissions) { - if (setDeviceRouteSelected && !Flags.enableMirroringInMediaRouter2()) { + if (!Flags.enableMirroringInMediaRouter2() && setDeviceRouteSelected) { // Return a fake system session that shows the device route as selected and // available bluetooth routes as transferable. - return userRecord.mHandler.getSystemProvider() - .generateDeviceRouteSelectedSessionInfo(targetPackageName); + return systemProvider.generateDeviceRouteSelectedSessionInfo( + targetPackageName); } else { - sessionInfos = userRecord.mHandler.getSystemProvider().getSessionInfos(); - if (!sessionInfos.isEmpty()) { - // Return a copy of the current system session with no modification, - // except setting the client package name. - return new RoutingSessionInfo.Builder(sessionInfos.get(0)) - .setClientPackageName(targetPackageName) - .build(); + RoutingSessionInfo session = + systemProvider.getSessionForPackage(targetPackageName); + if (session != null) { + return session; } else { Slog.w(TAG, "System provider does not have any session info."); + return null; } } } else { - return new RoutingSessionInfo.Builder( - userRecord.mHandler.getSystemProvider().getDefaultSessionInfo()) + return new RoutingSessionInfo.Builder(systemProvider.getDefaultSessionInfo()) .setClientPackageName(targetPackageName) .build(); } } - return null; } finally { Binder.restoreCallingIdentity(token); } @@ -2638,10 +2634,17 @@ class MediaRouter2ServiceImpl { } @Override - public void onSessionUpdated(@NonNull MediaRoute2Provider provider, - @NonNull RoutingSessionInfo sessionInfo) { - sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler, - this, provider, sessionInfo)); + public void onSessionUpdated( + @NonNull MediaRoute2Provider provider, + @NonNull RoutingSessionInfo sessionInfo, + Set<String> packageNamesWithRoutingSessionOverrides) { + sendMessage( + PooledLambda.obtainMessage( + UserHandler::onSessionInfoChangedOnHandler, + this, + provider, + sessionInfo, + packageNamesWithRoutingSessionOverrides)); } @Override @@ -3152,10 +3155,31 @@ class MediaRouter2ServiceImpl { toOriginalRequestId(uniqueRequestId), sessionInfo); } - private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider, - @NonNull RoutingSessionInfo sessionInfo) { + /** + * Implementation of {@link MediaRoute2Provider.Callback#onSessionUpdated}. + * + * <p>Must run on the thread that corresponds to this {@link UserHandler}. + */ + private void onSessionInfoChangedOnHandler( + @NonNull MediaRoute2Provider provider, + @NonNull RoutingSessionInfo sessionInfo, + Set<String> packageNamesWithRoutingSessionOverrides) { List<ManagerRecord> managers = getManagerRecords(); for (ManagerRecord manager : managers) { + if (Flags.enableMirroringInMediaRouter2()) { + String targetPackageName = manager.mTargetPackageName; + boolean skipDueToOverride = + targetPackageName != null + && packageNamesWithRoutingSessionOverrides.contains( + targetPackageName); + boolean sessionIsForTargetPackage = + TextUtils.isEmpty(sessionInfo.getClientPackageName()) // is global. + || TextUtils.equals( + targetPackageName, sessionInfo.getClientPackageName()); + if (skipDueToOverride || !sessionIsForTargetPackage) { + continue; + } + } manager.notifySessionUpdated(sessionInfo); } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index b93846bf9ee7..60fced1e0c51 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -62,7 +62,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { static final String SYSTEM_SESSION_ID = "SYSTEM_SESSION"; private final AudioManager mAudioManager; - private final Handler mHandler; + protected final Handler mHandler; private final Context mContext; private final UserHandle mUser; @@ -116,7 +116,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { () -> { publishProviderState(); if (updateSessionInfosIfNeeded()) { - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } }); @@ -129,7 +129,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { () -> { publishProviderState(); if (updateSessionInfosIfNeeded()) { - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } })); } @@ -161,7 +161,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { public void setCallback(Callback callback) { super.setCallback(callback); notifyProviderState(); - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } @Override @@ -296,7 +296,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses() && updateSessionInfosIfNeeded()) { - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } } @@ -327,6 +327,23 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } /** + * Returns the {@link RoutingSessionInfo} that corresponds to the package with the given name. + */ + public RoutingSessionInfo getSessionForPackage(String targetPackageName) { + synchronized (mLock) { + if (!mSessionInfos.isEmpty()) { + // Return a copy of the current system session with no modification, + // except setting the client package name. + return new RoutingSessionInfo.Builder(mSessionInfos.get(0)) + .setClientPackageName(targetPackageName) + .build(); + } else { + return null; + } + } + } + + /** * Builds a system {@link RoutingSessionInfo} with the selected route set to the currently * selected <b>device</b> route (wired or built-in, but not bluetooth) and transferable routes * set to the currently available (connected) bluetooth routes. @@ -626,20 +643,21 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { notifyProviderState(); } - void notifySessionInfoUpdated() { + void notifyGlobalSessionInfoUpdated() { if (mCallback == null) { return; } RoutingSessionInfo sessionInfo; synchronized (mLock) { - sessionInfo = mSessionInfos.get(0); - if (sessionInfo == null) { + if (mSessionInfos.isEmpty()) { return; } + sessionInfo = mSessionInfos.get(0); } - mCallback.onSessionUpdated(this, sessionInfo); + mCallback.onSessionUpdated( + this, sessionInfo, /* packageNamesWithRoutingSessionOverrides= */ Set.of()); } @Override diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java index 7dc30ab66fd2..8931e3a1426e 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java @@ -18,23 +18,33 @@ package com.android.server.media; import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.media.MediaRoute2ProviderService; +import android.media.MediaRoute2ProviderService.Reason; +import android.media.MediaRouter2Utils; import android.media.RoutingSessionInfo; +import android.os.Binder; import android.os.Looper; +import android.os.Process; import android.os.UserHandle; -import android.util.ArraySet; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; +import android.util.LongSparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.server.media.MediaRoute2ProviderServiceProxy.SystemMediaSessionCallback; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.stream.Stream; /** @@ -48,11 +58,33 @@ import java.util.stream.Stream; private static final String ROUTE_ID_PREFIX_SYSTEM = "SYSTEM"; private static final String ROUTE_ID_SYSTEM_SEPARATOR = "."; + private final PackageManager mPackageManager; + @GuardedBy("mLock") private MediaRoute2ProviderInfo mLastSystemProviderInfo; @GuardedBy("mLock") - private final Map<String, ProviderProxyRecord> mProxyRecords = new HashMap<>(); + private final Map<String, ProviderProxyRecord> mProxyRecords = new ArrayMap<>(); + + /** + * Maps package names to corresponding sessions maintained by {@link MediaRoute2ProviderService + * provider services}. + */ + @GuardedBy("mLock") + private final Map<String, SystemMediaSessionRecord> mPackageNameToSessionRecord = + new ArrayMap<>(); + + /** + * Maps route {@link MediaRoute2Info#getOriginalId original ids} to the id of the {@link + * MediaRoute2ProviderService provider service} that manages the corresponding route. + */ + @GuardedBy("mLock") + private final Map<String, String> mOriginalRouteIdToProviderId = new ArrayMap<>(); + + /** Maps request ids to pending session creation callbacks. */ + @GuardedBy("mLock") + private final LongSparseArray<SystemMediaSessionCallbackImpl> mPendingSessionCreations = + new LongSparseArray<>(); private static final ComponentName COMPONENT_NAME = new ComponentName( @@ -69,6 +101,128 @@ import java.util.stream.Stream; private SystemMediaRoute2Provider2(Context context, UserHandle user, Looper looper) { super(context, COMPONENT_NAME, user, looper); + mPackageManager = context.getPackageManager(); + } + + @Override + public void transferToRoute( + long requestId, + @NonNull UserHandle clientUserHandle, + @NonNull String clientPackageName, + String sessionOriginalId, + String routeOriginalId, + int transferReason) { + synchronized (mLock) { + var targetProviderProxyId = mOriginalRouteIdToProviderId.get(routeOriginalId); + var targetProviderProxyRecord = mProxyRecords.get(targetProviderProxyId); + // Holds the target route, if it's managed by a provider service. Holds null otherwise. + var serviceTargetRoute = + targetProviderProxyRecord != null + ? targetProviderProxyRecord.getRouteByOriginalId(routeOriginalId) + : null; + var existingSessionRecord = mPackageNameToSessionRecord.get(clientPackageName); + if (existingSessionRecord != null) { + var existingSession = existingSessionRecord.mSourceSessionInfo; + if (targetProviderProxyId != null + && TextUtils.equals( + targetProviderProxyId, existingSession.getProviderId())) { + // The currently selected route and target route both belong to the same + // provider. We tell the provider to handle the transfer. + targetProviderProxyRecord.requestTransfer( + existingSession.getOriginalId(), serviceTargetRoute); + } else { + // The target route is handled by a provider other than the target one. We need + // to release the existing session. + var currentProxyRecord = existingSessionRecord.getProxyRecord(); + if (currentProxyRecord != null) { + currentProxyRecord.releaseSession( + requestId, existingSession.getOriginalId()); + existingSessionRecord.removeSelfFromSessionMap(); + } + } + } + + if (serviceTargetRoute != null) { + boolean isGlobalSession = TextUtils.isEmpty(clientPackageName); + int uid; + if (isGlobalSession) { + uid = Process.INVALID_UID; + } else { + uid = fetchUid(clientPackageName, clientUserHandle); + if (uid == Process.INVALID_UID) { + throw new IllegalArgumentException( + "Cannot resolve transfer for " + + clientPackageName + + " and " + + clientUserHandle); + } + } + var pendingCreationCallback = + new SystemMediaSessionCallbackImpl( + targetProviderProxyId, requestId, clientPackageName); + mPendingSessionCreations.put(requestId, pendingCreationCallback); + targetProviderProxyRecord.requestCreateSystemMediaSession( + requestId, + uid, + clientPackageName, + routeOriginalId, + pendingCreationCallback); + } else { + // The target route is not provided by any of the services. Assume it's a system + // provided route. + super.transferToRoute( + requestId, + clientUserHandle, + clientPackageName, + sessionOriginalId, + routeOriginalId, + transferReason); + } + } + } + + @Nullable + @Override + public RoutingSessionInfo getSessionForPackage(String packageName) { + synchronized (mLock) { + var systemSession = super.getSessionForPackage(packageName); + if (systemSession == null) { + return null; + } + var overridingSession = mPackageNameToSessionRecord.get(packageName); + if (overridingSession != null) { + var builder = + new RoutingSessionInfo.Builder(overridingSession.mTranslatedSessionInfo) + .setProviderId(mUniqueId) + .setSystemSession(true); + for (var systemRoute : mLastSystemProviderInfo.getRoutes()) { + builder.addTransferableRoute(systemRoute.getOriginalId()); + } + return builder.build(); + } else { + return systemSession; + } + } + } + + /** + * Returns the uid that corresponds to the given name and user handle, or {@link + * Process#INVALID_UID} if a uid couldn't be found. + */ + @SuppressLint("MissingPermission") + // We clear the calling identity before calling the package manager, and we are running on the + // system_server. + private int fetchUid(String clientPackageName, UserHandle clientUserHandle) { + final long token = Binder.clearCallingIdentity(); + try { + return mPackageManager.getApplicationInfoAsUser( + clientPackageName, /* flags= */ 0, clientUserHandle) + .uid; + } catch (PackageManager.NameNotFoundException e) { + return Process.INVALID_UID; + } finally { + Binder.restoreCallingIdentity(token); + } } @Override @@ -85,21 +239,21 @@ import java.util.stream.Stream; } else { mProxyRecords.put(serviceProxy.mUniqueId, proxyRecord); } - setProviderState(buildProviderInfo()); + updateProviderInfo(); } updateSessionInfo(); notifyProviderState(); - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } @Override public void onSystemProviderRoutesChanged(MediaRoute2ProviderInfo providerInfo) { synchronized (mLock) { mLastSystemProviderInfo = providerInfo; - setProviderState(buildProviderInfo()); + updateProviderInfo(); } updateSessionInfo(); - notifySessionInfoUpdated(); + notifyGlobalSessionInfoUpdated(); } /** @@ -116,10 +270,13 @@ import java.util.stream.Stream; var builder = new RoutingSessionInfo.Builder(systemSessionInfo); mProxyRecords.values().stream() .flatMap(ProviderProxyRecord::getRoutesStream) - .map(MediaRoute2Info::getId) + .map(MediaRoute2Info::getOriginalId) .forEach(builder::addTransferableRoute); mSessionInfos.clear(); mSessionInfos.add(builder.build()); + for (var sessionRecords : mPackageNameToSessionRecord.values()) { + mSessionInfos.add(sessionRecords.mTranslatedSessionInfo); + } } } @@ -129,13 +286,84 @@ import java.util.stream.Stream; * provider services}. */ @GuardedBy("mLock") - private MediaRoute2ProviderInfo buildProviderInfo() { + private void updateProviderInfo() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(mLastSystemProviderInfo); - mProxyRecords.values().stream() - .flatMap(ProviderProxyRecord::getRoutesStream) - .forEach(builder::addRoute); - return builder.build(); + mOriginalRouteIdToProviderId.clear(); + for (var proxyRecord : mProxyRecords.values()) { + String proxyId = proxyRecord.mProxy.mUniqueId; + proxyRecord + .getRoutesStream() + .forEach( + route -> { + builder.addRoute(route); + mOriginalRouteIdToProviderId.put(route.getOriginalId(), proxyId); + }); + } + setProviderState(builder.build()); + } + + @Override + /* package */ void notifyGlobalSessionInfoUpdated() { + if (mCallback == null) { + return; + } + + RoutingSessionInfo sessionInfo; + Set<String> packageNamesWithRoutingSessionOverrides; + synchronized (mLock) { + if (mSessionInfos.isEmpty()) { + return; + } + packageNamesWithRoutingSessionOverrides = mPackageNameToSessionRecord.keySet(); + sessionInfo = mSessionInfos.getFirst(); + } + + mCallback.onSessionUpdated(this, sessionInfo, packageNamesWithRoutingSessionOverrides); + } + + private void onSessionOverrideUpdated(RoutingSessionInfo sessionInfo) { + // TODO: b/362507305 - Consider adding routes from other provider services. This is not a + // trivial change because a provider1-route to provider2-route transfer has seemingly two + // possible approachies. Either we first release the current session and then create the new + // one, in which case the audio is briefly going to leak through the system route. On the + // other hand, if we first create the provider2 session, then there will be a period during + // which there will be two overlapping routing policies asking for the exact same media + // stream. + var builder = new RoutingSessionInfo.Builder(sessionInfo); + mLastSystemProviderInfo.getRoutes().stream() + .map(MediaRoute2Info::getOriginalId) + .forEach(builder::addTransferableRoute); + mCallback.onSessionUpdated( + /* provider= */ this, + builder.build(), + /* packageNamesWithRoutingSessionOverrides= */ Set.of()); + } + + /** + * Equivalent to {@link #asSystemRouteId}, except it takes a unique route id instead of a + * original id. + */ + private static String uniqueIdAsSystemRouteId(String providerId, String uniqueRouteId) { + return asSystemRouteId(providerId, MediaRouter2Utils.getOriginalId(uniqueRouteId)); + } + + /** + * Returns a unique {@link MediaRoute2Info#getOriginalId() original id} for this provider to + * publish system media routes from {@link MediaRoute2ProviderService provider services}. + * + * <p>This provider will publish system media routes as part of the system routing session. + * However, said routes may also support {@link MediaRoute2Info#FLAG_ROUTING_TYPE_REMOTE remote + * routing}, meaning we cannot use the same id, or there would be an id collision. As a result, + * we derive a {@link MediaRoute2Info#getOriginalId original id} that is unique among all + * original route ids used by this provider. + */ + private static String asSystemRouteId(String providerId, String originalRouteId) { + return ROUTE_ID_PREFIX_SYSTEM + + ROUTE_ID_SYSTEM_SEPARATOR + + providerId + + ROUTE_ID_SYSTEM_SEPARATOR + + originalRouteId; } /** @@ -145,14 +373,69 @@ import java.util.stream.Stream; * @param mProxy The corresponding {@link MediaRoute2ProviderServiceProxy}. * @param mSystemMediaRoutes The last snapshot of routes from the service that support system * media routing, as defined by {@link MediaRoute2Info#supportsSystemMediaRouting()}. + * @param mNewOriginalIdToSourceOriginalIdMap Maps the {@link #mSystemMediaRoutes} ids to the + * original ids of corresponding {@link MediaRoute2ProviderService service} route. */ private record ProviderProxyRecord( MediaRoute2ProviderServiceProxy mProxy, - Collection<MediaRoute2Info> mSystemMediaRoutes) { + Map<String, MediaRoute2Info> mSystemMediaRoutes, + Map<String, String> mNewOriginalIdToSourceOriginalIdMap) { /** Returns a stream representation of the {@link #mSystemMediaRoutes}. */ public Stream<MediaRoute2Info> getRoutesStream() { - return mSystemMediaRoutes.stream(); + return mSystemMediaRoutes.values().stream(); + } + + @Nullable + public MediaRoute2Info getRouteByOriginalId(String routeOriginalId) { + return mSystemMediaRoutes.get(routeOriginalId); + } + + /** + * Requests the creation of a system media routing session. + * + * @param requestId The request id. + * @param uid The uid of the package whose media to route, or {@link Process#INVALID_UID} if + * not applicable. + * @param packageName The name of the package whose media to route. + * @param originalRouteId The {@link MediaRoute2Info#getOriginalId() original route id} of + * the route that should be initially selected. + * @param callback A {@link MediaRoute2ProviderServiceProxy.SystemMediaSessionCallback} for + * events. + * @see MediaRoute2ProviderService#onCreateSystemRoutingSession + */ + public void requestCreateSystemMediaSession( + long requestId, + int uid, + String packageName, + String originalRouteId, + SystemMediaSessionCallback callback) { + var targetRouteId = mNewOriginalIdToSourceOriginalIdMap.get(originalRouteId); + if (targetRouteId == null) { + Log.w( + TAG, + "Failed system media session creation due to lack of mapping for id: " + + originalRouteId); + callback.onRequestFailed( + requestId, MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE); + } else { + mProxy.requestCreateSystemMediaSession( + requestId, + uid, + packageName, + targetRouteId, + /* sessionHints= */ null, + callback); + } + } + + public void requestTransfer(String sessionId, MediaRoute2Info targetRoute) { + // TODO: Map the target route to the source route original id. + throw new UnsupportedOperationException("TODO Implement"); + } + + public void releaseSession(long requestId, String originalSessionId) { + mProxy.releaseSession(requestId, originalSessionId); } /** @@ -165,22 +448,177 @@ import java.util.stream.Stream; if (providerInfo == null) { return null; } - ArraySet<MediaRoute2Info> routes = new ArraySet<>(); - providerInfo.getRoutes().stream() - .filter(MediaRoute2Info::supportsSystemMediaRouting) - .forEach( - route -> { - String id = - ROUTE_ID_PREFIX_SYSTEM - + route.getProviderId() - + ROUTE_ID_SYSTEM_SEPARATOR - + route.getOriginalId(); - routes.add( - new MediaRoute2Info.Builder(id, route.getName()) - .addFeature(FEATURE_LIVE_AUDIO) - .build()); - }); - return new ProviderProxyRecord(serviceProxy, Collections.unmodifiableSet(routes)); + Map<String, MediaRoute2Info> routesMap = new ArrayMap<>(); + Map<String, String> idMap = new ArrayMap<>(); + for (MediaRoute2Info sourceRoute : providerInfo.getRoutes()) { + if (!sourceRoute.supportsSystemMediaRouting()) { + continue; + } + String id = + asSystemRouteId(providerInfo.getUniqueId(), sourceRoute.getOriginalId()); + var newRoute = + new MediaRoute2Info.Builder(id, sourceRoute.getName()) + .addFeature(FEATURE_LIVE_AUDIO) + .build(); + routesMap.put(id, newRoute); + idMap.put(id, sourceRoute.getOriginalId()); + } + return new ProviderProxyRecord( + serviceProxy, + Collections.unmodifiableMap(routesMap), + Collections.unmodifiableMap(idMap)); + } + } + + private class SystemMediaSessionCallbackImpl implements SystemMediaSessionCallback { + + private final String mProviderId; + private final long mRequestId; + private final String mClientPackageName; + // Accessed only on mHandler. + @Nullable private SystemMediaSessionRecord mSessionRecord; + + private SystemMediaSessionCallbackImpl( + String providerId, long requestId, String clientPackageName) { + mProviderId = providerId; + mRequestId = requestId; + mClientPackageName = clientPackageName; + } + + @Override + public void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo) { + mHandler.post( + () -> { + if (mSessionRecord != null) { + mSessionRecord.onSessionUpdate(sessionInfo); + } + SystemMediaSessionRecord systemMediaSessionRecord = + new SystemMediaSessionRecord(mProviderId, sessionInfo); + RoutingSessionInfo translatedSession; + synchronized (mLock) { + mSessionRecord = systemMediaSessionRecord; + mPackageNameToSessionRecord.put( + mClientPackageName, systemMediaSessionRecord); + mPendingSessionCreations.remove(mRequestId); + translatedSession = systemMediaSessionRecord.mTranslatedSessionInfo; + } + onSessionOverrideUpdated(translatedSession); + }); + } + + @Override + public void onRequestFailed(long requestId, @Reason int reason) { + mHandler.post( + () -> { + if (mSessionRecord != null) { + mSessionRecord.onRequestFailed(requestId, reason); + } + synchronized (mLock) { + mPendingSessionCreations.remove(mRequestId); + } + notifyRequestFailed(requestId, reason); + }); + } + + @Override + public void onSessionReleased() { + mHandler.post( + () -> { + if (mSessionRecord != null) { + mSessionRecord.onSessionReleased(); + } else { + // Should never happen. The session hasn't yet been created. + throw new IllegalStateException(); + } + }); + } + } + + private class SystemMediaSessionRecord implements SystemMediaSessionCallback { + + private final String mProviderId; + + @GuardedBy("SystemMediaRoute2Provider2.this.mLock") + @NonNull + private RoutingSessionInfo mSourceSessionInfo; + + /** + * The same as {@link #mSourceSessionInfo}, except ids are {@link #asSystemRouteId system + * provider ids}. + */ + @GuardedBy("SystemMediaRoute2Provider2.this.mLock") + @NonNull + private RoutingSessionInfo mTranslatedSessionInfo; + + SystemMediaSessionRecord( + @NonNull String providerId, @NonNull RoutingSessionInfo sessionInfo) { + mProviderId = providerId; + mSourceSessionInfo = sessionInfo; + mTranslatedSessionInfo = asSystemProviderSession(sessionInfo); + } + + @Override + public void onSessionUpdate(@NonNull RoutingSessionInfo sessionInfo) { + RoutingSessionInfo translatedSessionInfo = mTranslatedSessionInfo; + synchronized (mLock) { + mSourceSessionInfo = sessionInfo; + mTranslatedSessionInfo = asSystemProviderSession(sessionInfo); + } + onSessionOverrideUpdated(translatedSessionInfo); + } + + @Override + public void onRequestFailed(long requestId, @Reason int reason) { + notifyRequestFailed(requestId, reason); + } + + @Override + public void onSessionReleased() { + synchronized (mLock) { + removeSelfFromSessionMap(); + } + notifyGlobalSessionInfoUpdated(); + } + + @GuardedBy("SystemMediaRoute2Provider2.this.mLock") + @Nullable + public ProviderProxyRecord getProxyRecord() { + ProviderProxyRecord provider = mProxyRecords.get(mProviderId); + if (provider == null) { + // Unexpected condition where the proxy is no longer available while there's an + // ongoing session. Could happen due to a crash in the provider process. + removeSelfFromSessionMap(); + } + return provider; + } + + @GuardedBy("SystemMediaRoute2Provider2.this.mLock") + private void removeSelfFromSessionMap() { + mPackageNameToSessionRecord.remove(mSourceSessionInfo.getClientPackageName()); + } + + private RoutingSessionInfo asSystemProviderSession(RoutingSessionInfo session) { + var builder = + new RoutingSessionInfo.Builder(session) + .setProviderId(mUniqueId) + .setSystemSession(true) + .clearSelectedRoutes() + .clearSelectableRoutes() + .clearDeselectableRoutes() + .clearTransferableRoutes(); + session.getSelectedRoutes().stream() + .map(it -> uniqueIdAsSystemRouteId(session.getProviderId(), it)) + .forEach(builder::addSelectedRoute); + session.getSelectableRoutes().stream() + .map(it -> uniqueIdAsSystemRouteId(session.getProviderId(), it)) + .forEach(builder::addSelectableRoute); + session.getDeselectableRoutes().stream() + .map(it -> uniqueIdAsSystemRouteId(session.getProviderId(), it)) + .forEach(builder::addDeselectableRoute); + session.getTransferableRoutes().stream() + .map(it -> uniqueIdAsSystemRouteId(session.getProviderId(), it)) + .forEach(builder::addTransferableRoute); + return builder.build(); } } } diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 89902f7f8321..7cbbe2938fd5 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -101,4 +101,10 @@ 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); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c6d7fc7508da..7375a68c547b 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -112,6 +112,7 @@ import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_ import static android.service.notification.Flags.callstyleCallbackApi; import static android.service.notification.Flags.notificationClassification; import static android.service.notification.Flags.notificationForceGrouping; +import static android.service.notification.Flags.notificationRegroupOnClassification; import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle; import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; @@ -1851,6 +1852,42 @@ public class NotificationManagerService extends SystemService { } } + @Override + public void unbundleNotification(String key) { + if (!(notificationClassification() && notificationRegroupOnClassification())) { + return; + } + synchronized (mNotificationLock) { + NotificationRecord r = mNotificationsByKey.get(key); + if (r == null) { + return; + } + + if (DBG) { + Slog.v(TAG, "unbundleNotification: " + 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); + if (originalChannel != null && !origChannelId.equals(r.getChannel().getId())) { + r.updateNotificationChannel(originalChannel); + mGroupHelper.onNotificationUnbundled(r, hasOriginalSummary); + } + } + } }; NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 749952e3336f..15377d6b269a 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -559,7 +559,7 @@ public class PreferencesHelper implements RankingConfig { if (r.uid == UNKNOWN_UID) { if (Flags.persistIncompleteRestoreData()) { - r.userId = userId; + r.userIdWhenUidUnknown = userId; } mRestoredWithoutUids.put(unrestoredPackageKey(pkg, userId), r); } else { @@ -756,7 +756,7 @@ public class PreferencesHelper implements RankingConfig { if (Flags.persistIncompleteRestoreData() && r.uid == UNKNOWN_UID) { out.attributeLong(null, ATT_CREATION_TIME, r.creationTime); - out.attributeInt(null, ATT_USERID, r.userId); + out.attributeInt(null, ATT_USERID, r.userIdWhenUidUnknown); } if (!forBackup) { @@ -1959,7 +1959,7 @@ public class PreferencesHelper implements RankingConfig { ArrayList<ZenBypassingApp> bypassing = new ArrayList<>(); synchronized (mLock) { for (PackagePreferences p : mPackagePreferences.values()) { - if (p.userId != userId) { + if (UserHandle.getUserId(p.uid) != userId) { continue; } int totalChannelCount = p.channels.size(); @@ -3189,7 +3189,7 @@ public class PreferencesHelper implements RankingConfig { // Until we enable the UI, we should return false. boolean canHavePromotedNotifs = android.app.Flags.uiRichOngoing(); - @UserIdInt int userId; + @UserIdInt int userIdWhenUidUnknown; Delegate delegate = null; ArrayMap<String, NotificationChannel> channels = new ArrayMap<>(); diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 3528d3d96c2b..8a35006e0f6a 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -487,6 +487,20 @@ public interface Computer extends PackageDataSnapshot { ProviderInfo resolveContentProvider(@NonNull String name, @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid); + /** + * Resolves a ContentProvider on behalf of a UID + * @param name Authority of the content provider + * @param flags option flags to modify the data returned. + * @param userId Current user ID + * @param filterCallingUid UID of the caller who's access to the content provider + * is to be checked + * @return + */ + @Nullable + ProviderInfo resolveContentProviderForUid(@NonNull String name, + @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, + int filterCallingUid); + @Nullable ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid, @NonNull String visibleAuthority); diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index be2f58dc276c..38617621bf89 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -4749,6 +4749,38 @@ public class ComputerEngine implements Computer { @Nullable @Override + public ProviderInfo resolveContentProviderForUid(@NonNull String name, + @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, + int filterCallingUid) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.RESOLVE_COMPONENT_FOR_UID, + "resolveContentProviderForUid"); + + int callingUid = Binder.getCallingUid(); + int filterUserId = UserHandle.getUserId(filterCallingUid); + enforceCrossUserPermission(callingUid, filterUserId, false, false, + "resolveContentProviderForUid"); + + // Real callingUid should be able to see filterCallingUid + if (filterAppAccess(filterCallingUid, callingUid)) { + return null; + } + + ProviderInfo pInfo = resolveContentProvider(name, flags, userId, filterCallingUid); + if (pInfo == null) { + return null; + } + // Real callingUid should be able to see the ContentProvider accessible to filterCallingUid + ProviderInfo pInfo2 = resolveContentProvider(name, flags, userId, callingUid); + if (pInfo2 != null + && Objects.equals(pInfo.name, pInfo2.name) + && Objects.equals(pInfo.authority, pInfo2.authority)) { + return pInfo; + } + return null; + } + + @Nullable + @Override public ProviderInfo resolveContentProvider(@NonNull String name, @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid) { diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index f05c54d666df..b11d3499d391 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -1129,6 +1129,12 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { } @Override + public final ProviderInfo resolveContentProviderForUid(String name, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, int filterCallingUid) { + return snapshot().resolveContentProviderForUid(name, flags, userId, filterCallingUid); + } + + @Override @Deprecated public final void resetApplicationPreferences(int userId) { mPreferredActivityHelper.resetApplicationPreferences(userId); diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java index e9cb279439a6..e989d6875d15 100644 --- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java +++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java @@ -40,7 +40,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.OctFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; @@ -351,22 +351,22 @@ public interface AccessCheckDelegate extends CheckPermissionDelegate, CheckOpsDe @Override public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, - @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, SyncNotedAppOp> superImpl) { + @Nullable String message, boolean shouldCollectMessage, int notedCount, + @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, Integer, SyncNotedAppOp> superImpl) { if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage); + shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); } finally { Binder.restoreCallingIdentity(identity); } } return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage); + shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); } @Override diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 3f9144f0d980..dea52fd7cd99 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -53,7 +53,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.OctFunction; +import com.android.internal.util.function.NonaFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; @@ -248,11 +248,12 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String, - Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { + boolean shouldCollectMessage, int notedCount, + @NonNull NonaFunction<Integer, Integer, String, String, + Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) { return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), resolveUid(code, uid), packageName, attributionTag, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage); + shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); } @Override diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c4d1cc723804..ec0f25169d75 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4068,7 +4068,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Nullable IBinder focusedToken) { boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event, focusedToken); - if (handled && Arrays.stream(event.getKeycodes()).anyMatch( + if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch( (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) { mPowerKeyHandled = true; } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 0c3c46c75eee..7f88e7463208 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -479,6 +479,7 @@ public class Notifier { case PowerManager.PARTIAL_WAKE_LOCK: return BatteryStats.WAKE_TYPE_PARTIAL; + case PowerManager.FULL_WAKE_LOCK: case PowerManager.SCREEN_DIM_WAKE_LOCK: case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: return BatteryStats.WAKE_TYPE_FULL; @@ -503,6 +504,31 @@ public class Notifier { } } + @VisibleForTesting + int getWakelockMonitorTypeForLogging(int flags) { + switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) { + case PowerManager.FULL_WAKE_LOCK, PowerManager.SCREEN_DIM_WAKE_LOCK, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK: + return PowerManager.FULL_WAKE_LOCK; + case PowerManager.DRAW_WAKE_LOCK: + return PowerManager.DRAW_WAKE_LOCK; + case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: + if (mSuspendWhenScreenOffDueToProximityConfig) { + return -1; + } + return PowerManager.PARTIAL_WAKE_LOCK; + case PowerManager.PARTIAL_WAKE_LOCK: + return PowerManager.PARTIAL_WAKE_LOCK; + case PowerManager.DOZE_WAKE_LOCK: + // Doze wake locks are an internal implementation detail of the + // communication between dream manager service and power manager + // service. They have no additive battery impact. + return -1; + default: + return -1; + } + } + /** * Notifies that the device is changing wakefulness. * This function may be called even if the previous change hasn't finished in @@ -1288,7 +1314,7 @@ public class Notifier { if (mBatteryStatsInternal == null) { return; } - final int type = flags & PowerManager.WAKE_LOCK_LEVEL_MASK; + final int type = getWakelockMonitorTypeForLogging(flags); if (workSource == null || workSource.isEmpty()) { final int mappedUid = mBatteryStatsInternal.getOwnerUid(ownerUid); mFrameworkStatsLogger.wakelockStateChanged(mappedUid, tag, type, eventType); diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 83461125b404..a0bc77e939d1 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -24,6 +24,7 @@ import static com.android.server.power.hint.Flags.cpuHeadroomAffinityCheck; import static com.android.server.power.hint.Flags.powerhintThreadCleanup; import static com.android.server.power.hint.Flags.resetOnForkEnabled; +import android.Manifest; import android.adpf.ISessionManager; import android.annotation.NonNull; import android.annotation.Nullable; @@ -59,6 +60,9 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SessionCreationConfig; import android.os.SystemProperties; +import android.os.UserHandle; +import android.system.Os; +import android.system.OsConstants; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -79,7 +83,10 @@ import com.android.server.SystemService; import com.android.server.power.hint.HintManagerService.AppHintSession.SessionModes; import com.android.server.utils.Slogf; +import java.io.BufferedReader; import java.io.FileDescriptor; +import java.io.FileReader; +import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Field; import java.util.ArrayList; @@ -95,6 +102,8 @@ import java.util.Set; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** An hint service implementation that runs in System Server process. */ public final class HintManagerService extends SystemService { @@ -103,10 +112,10 @@ public final class HintManagerService extends SystemService { private static final int EVENT_CLEAN_UP_UID = 3; @VisibleForTesting static final int CLEAN_UP_UID_DELAY_MILLIS = 1000; - // The minimum interval between the headroom calls as rate limiting. - private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000; - private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000; + // example: cpu 2255 34 2290 22625563 6290 127 456 + private static final Pattern PROC_STAT_CPU_TIME_TOTAL_PATTERN = + Pattern.compile("cpu\\s+(?<user>[0-9]+)\\s(?<nice>[0-9]+).+"); @VisibleForTesting final long mHintSessionPreferredRate; @@ -192,10 +201,26 @@ public final class HintManagerService extends SystemService { private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager"; private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms"; private static final String PROPERTY_CHECK_HEADROOM_TID = "persist.hms.check_headroom_tid"; - private static final String PROPERTY_CHECK_HEADROOM_AFFINITY = "persist.hms.check_affinity"; + private static final String PROPERTY_CHECK_HEADROOM_AFFINITY = + "persist.hms.check_headroom_affinity"; + private static final String PROPERTY_CHECK_HEADROOM_PROC_STAT_MIN_MILLIS = + "persist.hms.check_headroom_proc_stat_min_millis"; private Boolean mFMQUsesIntegratedEventFlag = false; private final Object mCpuHeadroomLock = new Object(); + @VisibleForTesting + final float mJiffyMillis; + private final int mCheckHeadroomProcStatMinMillis; + @GuardedBy("mCpuHeadroomLock") + private long mLastCpuUserModeTimeCheckedMillis = 0; + @GuardedBy("mCpuHeadroomLock") + private long mLastCpuUserModeJiffies = 0; + @GuardedBy("mCpuHeadroomLock") + private final Map<Integer, Long> mUidToLastUserModeJiffies; + @VisibleForTesting + private String mProcStatFilePathOverride = null; + @VisibleForTesting + private boolean mEnforceCpuHeadroomUserModeCpuTimeCheck = false; private ISessionManager mSessionManager; @@ -310,8 +335,16 @@ public final class HintManagerService extends SystemService { new GpuHeadroomParamsInternal().calculationWindowMillis; if (mSupportInfo.headroom.isCpuSupported) { mCpuHeadroomCache = new HeadroomCache<>(2, mSupportInfo.headroom.cpuMinIntervalMillis); + mUidToLastUserModeJiffies = new ArrayMap<>(); + long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK); + mJiffyMillis = 1000.0f / jiffyHz; + mCheckHeadroomProcStatMinMillis = SystemProperties.getInt( + PROPERTY_CHECK_HEADROOM_PROC_STAT_MIN_MILLIS, 50); } else { mCpuHeadroomCache = null; + mUidToLastUserModeJiffies = null; + mJiffyMillis = 0.0f; + mCheckHeadroomProcStatMinMillis = 0; } if (mSupportInfo.headroom.isGpuSupported) { mGpuHeadroomCache = new HeadroomCache<>(2, mSupportInfo.headroom.gpuMinIntervalMillis); @@ -370,6 +403,12 @@ public final class HintManagerService extends SystemService { return supportInfo; } + @VisibleForTesting + void setProcStatPathOverride(String override) { + mProcStatFilePathOverride = override; + mEnforceCpuHeadroomUserModeCpuTimeCheck = true; + } + private ServiceThread createCleanUpThread() { final ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_LOWEST, true /*allowIo*/); @@ -851,6 +890,11 @@ public final class HintManagerService extends SystemService { mChannelMap.remove(uid); } } + synchronized (mCpuHeadroomLock) { + if (mSupportInfo.headroom.isCpuSupported && mUidToLastUserModeJiffies != null) { + mUidToLastUserModeJiffies.remove(uid); + } + } }); } @@ -1230,7 +1274,7 @@ public final class HintManagerService extends SystemService { // Only call into AM if the tid is either isolated or invalid if (isolatedPids == null) { // To avoid deadlock, do not call into AMS if the call is from system. - if (uid == Process.SYSTEM_UID) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { return tid; } isolatedPids = mAmInternal.getIsolatedProcesses(uid); @@ -1485,14 +1529,17 @@ public final class HintManagerService extends SystemService { throw new UnsupportedOperationException(); } checkCpuHeadroomParams(params); + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); final CpuHeadroomParams halParams = new CpuHeadroomParams(); - halParams.tids = new int[]{Binder.getCallingPid()}; + halParams.tids = new int[]{pid}; halParams.calculationType = params.calculationType; halParams.calculationWindowMillis = params.calculationWindowMillis; if (params.usesDeviceHeadroom) { halParams.tids = new int[]{}; } else if (params.tids != null && params.tids.length > 0) { - if (SystemProperties.getBoolean(PROPERTY_CHECK_HEADROOM_TID, true)) { + if (UserHandle.getAppId(uid) != Process.SYSTEM_UID && SystemProperties.getBoolean( + PROPERTY_CHECK_HEADROOM_TID, true)) { final int tgid = Process.getThreadGroupLeader(Binder.getCallingPid()); for (int tid : params.tids) { if (Process.getThreadGroupLeader(tid) != tgid) { @@ -1515,6 +1562,20 @@ public final class HintManagerService extends SystemService { if (res != null) return res; } } + final boolean shouldCheckUserModeCpuTime = + mEnforceCpuHeadroomUserModeCpuTimeCheck + || (UserHandle.getAppId(uid) != Process.SYSTEM_UID + && mContext.checkCallingPermission( + Manifest.permission.DEVICE_POWER) + == PackageManager.PERMISSION_DENIED); + + if (shouldCheckUserModeCpuTime) { + synchronized (mCpuHeadroomLock) { + if (!checkPerUidUserModeCpuTimeElapsedLocked(uid)) { + return null; + } + } + } // return from HAL directly try { final CpuHeadroomResult result = mPowerHal.getCpuHeadroom(halParams); @@ -1528,6 +1589,11 @@ public final class HintManagerService extends SystemService { mCpuHeadroomCache.add(halParams, result); } } + if (shouldCheckUserModeCpuTime) { + synchronized (mCpuHeadroomLock) { + mUidToLastUserModeJiffies.put(uid, mLastCpuUserModeJiffies); + } + } return result; } catch (RemoteException e) { Slog.e(TAG, "Failed to get CPU headroom from Power HAL", e); @@ -1556,6 +1622,40 @@ public final class HintManagerService extends SystemService { } } + // check if there has been sufficient user mode cpu time elapsed since last call + // from the same uid + @GuardedBy("mCpuHeadroomLock") + private boolean checkPerUidUserModeCpuTimeElapsedLocked(int uid) { + // skip checking proc stat if it's within mCheckHeadroomProcStatMinMillis + if (System.currentTimeMillis() - mLastCpuUserModeTimeCheckedMillis + > mCheckHeadroomProcStatMinMillis) { + try { + mLastCpuUserModeJiffies = getUserModeJiffies(); + } catch (Exception e) { + Slog.e(TAG, "Failed to get user mode CPU time", e); + return false; + } + mLastCpuUserModeTimeCheckedMillis = System.currentTimeMillis(); + } + if (mUidToLastUserModeJiffies.containsKey(uid)) { + long uidLastUserModeJiffies = mUidToLastUserModeJiffies.get(uid); + if ((mLastCpuUserModeJiffies - uidLastUserModeJiffies) * mJiffyMillis + < mSupportInfo.headroom.cpuMinIntervalMillis) { + Slog.w(TAG, "UID " + uid + " is requesting CPU headroom too soon"); + Slog.d(TAG, "UID " + uid + " last request at " + + uidLastUserModeJiffies * mJiffyMillis + + "ms with device currently at " + + mLastCpuUserModeJiffies * mJiffyMillis + + "ms, the interval: " + + (mLastCpuUserModeJiffies - uidLastUserModeJiffies) + * mJiffyMillis + "ms is less than require minimum interval " + + mSupportInfo.headroom.cpuMinIntervalMillis + "ms"); + return false; + } + } + return true; + } + private void checkCpuHeadroomParams(CpuHeadroomParamsInternal params) { boolean calculationTypeMatched = false; try { @@ -1731,6 +1831,27 @@ public final class HintManagerService extends SystemService { } } + private long getUserModeJiffies() throws IOException { + String filePath = + mProcStatFilePathOverride == null ? "/proc/stat" : mProcStatFilePathOverride; + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + Matcher matcher = PROC_STAT_CPU_TIME_TOTAL_PATTERN.matcher(line.trim()); + if (matcher.find()) { + long userJiffies = Long.parseLong(matcher.group("user")); + long niceJiffies = Long.parseLong(matcher.group("nice")); + Slog.d(TAG, + "user: " + userJiffies + " nice: " + niceJiffies + + " total " + (userJiffies + niceJiffies)); + reader.close(); + return userJiffies + niceJiffies; + } + } + } + throw new IllegalStateException("Can't find cpu line in " + filePath); + } + private boolean checkGraphicsPipelineValid(SessionCreationConfig creationConfig, int uid) { if (creationConfig.modesToEnable == null) { return true; diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 1bed48a09d9e..2e6be5bb56a8 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -1251,12 +1251,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba // should document in PackageInstaller.SessionParams#setEnableRollback // After enabling and committing any rollback, observe packages and // prepare to rollback if packages crashes too frequently. - mPackageWatchdog.startExplicitHealthCheck(mPackageHealthObserver, - rollback.getPackageNames(), mRollbackLifetimeDurationInMillis); + mPackageWatchdog.startExplicitHealthCheck(rollback.getPackageNames(), + mRollbackLifetimeDurationInMillis, mPackageHealthObserver); } } else { - mPackageWatchdog.startExplicitHealthCheck(mPackageHealthObserver, - rollback.getPackageNames(), mRollbackLifetimeDurationInMillis); + mPackageWatchdog.startExplicitHealthCheck(rollback.getPackageNames(), + mRollbackLifetimeDurationInMillis, mPackageHealthObserver); } runExpiration(); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f8877ad912b5..c18918fd9f8b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -2175,6 +2175,19 @@ 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); + }); + } + @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java index dad3a784cfb9..bb163ef4c1d5 100644 --- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java +++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java @@ -369,10 +369,9 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener { tagName = parser.getName(); if (TAG_QUOTA.equals(tagName)) { CacheQuotaHint request = getRequestFromXml(parser); - if (request == null) { - continue; + if (request != null) { + quotas.add(request); } - quotas.add(request); } } eventType = parser.next(); diff --git a/services/core/java/com/android/server/updates/Android.bp b/services/core/java/com/android/server/updates/Android.bp deleted file mode 100644 index 10beebb82711..000000000000 --- a/services/core/java/com/android/server/updates/Android.bp +++ /dev/null @@ -1,11 +0,0 @@ -aconfig_declarations { - name: "updates_flags", - package: "com.android.server.updates", - container: "system", - srcs: ["*.aconfig"], -} - -java_aconfig_library { - name: "updates_flags_lib", - aconfig_declarations: "updates_flags", -} diff --git a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java deleted file mode 100644 index af4025e1db7c..000000000000 --- a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.updates; - -import android.content.Context; -import android.content.Intent; -import android.os.FileUtils; -import android.system.ErrnoException; -import android.system.Os; -import android.util.Slog; - -import libcore.io.Streams; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInstallReceiver { - - private static final String TAG = "CTLogInstallReceiver"; - private static final String LOGDIR_PREFIX = "logs-"; - - public CertificateTransparencyLogInstallReceiver() { - super("/data/misc/keychain/ct/", "ct_logs", "metadata/", "version"); - } - - @Override - protected void install(InputStream inputStream, int version) throws IOException { - if (!Flags.certificateTransparencyInstaller()) { - return; - } - // To support atomically replacing the old configuration directory with the new there's a - // bunch of steps. We create a new directory with the logs and then do an atomic update of - // the current symlink to point to the new directory. - // 1. Ensure that the update dir exists and is readable - updateDir.mkdir(); - if (!updateDir.isDirectory()) { - throw new IOException("Unable to make directory " + updateDir.getCanonicalPath()); - } - if (!updateDir.setReadable(true, false)) { - throw new IOException("Unable to set permissions on " + updateDir.getCanonicalPath()); - } - File currentSymlink = new File(updateDir, "current"); - File newVersion = new File(updateDir, LOGDIR_PREFIX + String.valueOf(version)); - // 2. Handle the corner case where the new directory already exists. - if (newVersion.exists()) { - // If the symlink has already been updated then the update died between steps 7 and 8 - // and so we cannot delete the directory since its in use. Instead just bump the version - // and return. - if (newVersion.getCanonicalPath().equals(currentSymlink.getCanonicalPath())) { - writeUpdate( - updateDir, - updateVersion, - new ByteArrayInputStream(Long.toString(version).getBytes())); - deleteOldLogDirectories(); - return; - } else { - FileUtils.deleteContentsAndDir(newVersion); - } - } - try { - // 3. Create /data/misc/keychain/ct/<new_version>/ . - newVersion.mkdir(); - if (!newVersion.isDirectory()) { - throw new IOException("Unable to make directory " + newVersion.getCanonicalPath()); - } - if (!newVersion.setReadable(true, false)) { - throw new IOException( - "Failed to set " + newVersion.getCanonicalPath() + " readable"); - } - - // 4. Validate the log list json and move the file in <new_version>/ . - installLogList(newVersion, inputStream); - - // 5. Create the temp symlink. We'll rename this to the target symlink to get an atomic - // update. - File tempSymlink = new File(updateDir, "new_symlink"); - try { - Os.symlink(newVersion.getCanonicalPath(), tempSymlink.getCanonicalPath()); - } catch (ErrnoException e) { - throw new IOException("Failed to create symlink", e); - } - - // 6. Update the symlink target, this is the actual update step. - tempSymlink.renameTo(currentSymlink.getAbsoluteFile()); - } catch (IOException | RuntimeException e) { - FileUtils.deleteContentsAndDir(newVersion); - throw e; - } - Slog.i(TAG, "CT log directory updated to " + newVersion.getAbsolutePath()); - // 7. Update the current version information - writeUpdate( - updateDir, - updateVersion, - new ByteArrayInputStream(Long.toString(version).getBytes())); - // 8. Cleanup - deleteOldLogDirectories(); - } - - @Override - protected void postInstall(Context context, Intent intent) { - if (!Flags.certificateTransparencyInstaller()) { - return; - } - } - - private void installLogList(File directory, InputStream inputStream) throws IOException { - try { - byte[] content = Streams.readFullyNoClose(inputStream); - if (new JSONObject(new String(content, StandardCharsets.UTF_8)).length() == 0) { - throw new IOException("Log list data not valid"); - } - - File file = new File(directory, "log_list.json"); - try (FileOutputStream outputStream = new FileOutputStream(file)) { - outputStream.write(content); - } - if (!file.setReadable(true, false)) { - throw new IOException("Failed to set permissions on " + file.getCanonicalPath()); - } - } catch (JSONException e) { - throw new IOException("Malformed json in log list", e); - } - } - - private void deleteOldLogDirectories() throws IOException { - if (!updateDir.exists()) { - return; - } - File currentTarget = new File(updateDir, "current").getCanonicalFile(); - FileFilter filter = - new FileFilter() { - @Override - public boolean accept(File file) { - return !currentTarget.equals(file) - && file.getName().startsWith(LOGDIR_PREFIX); - } - }; - for (File f : updateDir.listFiles(filter)) { - FileUtils.deleteContentsAndDir(f); - } - } -} diff --git a/services/core/java/com/android/server/updates/flags.aconfig b/services/core/java/com/android/server/updates/flags.aconfig deleted file mode 100644 index 476cb3723c97..000000000000 --- a/services/core/java/com/android/server/updates/flags.aconfig +++ /dev/null @@ -1,10 +0,0 @@ -package: "com.android.server.updates" -container: "system" - -flag { - name: "certificate_transparency_installer" - is_exported: true - namespace: "network_security" - description: "Enable certificate transparency installer for log list data" - bug: "319829948" -} diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index 19eba5fe5755..90c2216f6b22 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -51,8 +51,11 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.server.wm.utils.InsetUtils; +import com.android.window.flags.Flags; import java.io.PrintWriter; +import java.util.function.Consumer; +import java.util.function.Supplier; /** * Base class for a Snapshot controller @@ -148,43 +151,60 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, protected abstract Rect getLetterboxInsets(ActivityRecord topActivity); /** - * This is different than {@link #recordSnapshotInner(TYPE)} because it doesn't store - * the snapshot to the cache and returns the TaskSnapshot immediately. - * - * This is only used for testing so the snapshot content can be verified. + * This is different than {@link #recordSnapshotInner(TYPE, boolean, Consumer)} because it + * doesn't store the snapshot to the cache and returns the TaskSnapshot immediately. */ @VisibleForTesting - TaskSnapshot captureSnapshot(TYPE source) { - final TaskSnapshot snapshot; + SnapshotSupplier captureSnapshot(TYPE source, boolean allowAppTheme) { + final SnapshotSupplier supplier = new SnapshotSupplier(); switch (getSnapshotMode(source)) { - case SNAPSHOT_MODE_NONE: - return null; case SNAPSHOT_MODE_APP_THEME: - snapshot = drawAppThemeSnapshot(source); + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot"); + if (Flags.excludeDrawingAppThemeSnapshotFromLock()) { + if (allowAppTheme) { + supplier.setSupplier(drawAppThemeSnapshot(source)); + } + } else { + final Supplier<TaskSnapshot> original = drawAppThemeSnapshot(source); + final TaskSnapshot snapshot = original != null ? original.get() : null; + supplier.setSnapshot(snapshot); + } + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); break; case SNAPSHOT_MODE_REAL: - snapshot = snapshot(source); + supplier.setSnapshot(snapshot(source)); break; default: - snapshot = null; break; } - return snapshot; + return supplier; } - final TaskSnapshot recordSnapshotInner(TYPE source) { + /** + * @param allowAppTheme If true, allows to draw app theme snapshot when it's not allowed to take + * a real screenshot, but create a fake representation of the app. + * @param inLockConsumer Extra task to do in WM lock when first get the snapshot object. + */ + final SnapshotSupplier recordSnapshotInner(TYPE source, boolean allowAppTheme, + @Nullable Consumer<TaskSnapshot> inLockConsumer) { if (shouldDisableSnapshots()) { return null; } - final TaskSnapshot snapshot = captureSnapshot(source); - if (snapshot == null) { - return null; - } - mCache.putSnapshot(source, snapshot); - return snapshot; + final SnapshotSupplier supplier = captureSnapshot(source, allowAppTheme); + supplier.setConsumer(t -> { + synchronized (mService.mGlobalLock) { + if (!source.isAttached()) { + return; + } + mCache.putSnapshot(source, t); + if (inLockConsumer != null) { + inLockConsumer.accept(t); + } + } + }); + return supplier; } - @VisibleForTesting int getSnapshotMode(TYPE source) { final int type = source.getActivityType(); if (type == ACTIVITY_TYPE_RECENTS || type == ACTIVITY_TYPE_DREAM) { @@ -400,7 +420,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, * If we are not allowed to take a real screenshot, this attempts to represent the app as best * as possible by using the theme's window background. */ - private TaskSnapshot drawAppThemeSnapshot(TYPE source) { + private Supplier<TaskSnapshot> drawAppThemeSnapshot(TYPE source) { final ActivityRecord topActivity = getTopActivity(source); if (topActivity == null) { return null; @@ -432,26 +452,46 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, decorPainter.setInsets(systemBarInsets); decorPainter.drawDecors(c /* statusBarExcludeFrame */, null /* alreadyDrawFrame */); node.end(c); - final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); - if (hwBitmap == null) { - return null; - } + final Rect contentInsets = new Rect(systemBarInsets); final Rect letterboxInsets = getLetterboxInsets(topActivity); InsetUtils.addInsets(contentInsets, letterboxInsets); - // Note, the app theme snapshot is never translucent because we enforce a non-translucent - // color above - final TaskSnapshot taskSnapshot = new TaskSnapshot( - System.currentTimeMillis() /* id */, - SystemClock.elapsedRealtimeNanos() /* captureTime */, - topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(), - hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, - mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight), - contentInsets, letterboxInsets, false /* isLowResolution */, - false /* isRealSnapshot */, source.getWindowingMode(), - attrs.insetsFlags.appearance, false /* isTranslucent */, false /* hasImeSurface */, - topActivity.getConfiguration().uiMode /* uiMode */); - return validateSnapshot(taskSnapshot); + + final TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); + builder.setIsRealSnapshot(false); + builder.setId(System.currentTimeMillis()); + builder.setContentInsets(contentInsets); + builder.setLetterboxInsets(letterboxInsets); + + builder.setTopActivityComponent(topActivity.mActivityComponent); + // Note, the app theme snapshot is never translucent because we enforce a + // non-translucent color above. + builder.setIsTranslucent(false); + builder.setWindowingMode(source.getWindowingMode()); + builder.setAppearance(attrs.insetsFlags.appearance); + builder.setUiMode(topActivity.getConfiguration().uiMode); + + builder.setRotation(mainWindow.getWindowConfiguration().getRotation()); + builder.setOrientation(mainWindow.getConfiguration().orientation); + builder.setTaskSize(new Point(taskWidth, taskHeight)); + builder.setCaptureTime(SystemClock.elapsedRealtimeNanos()); + + return () -> { + try { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "drawAppThemeSnapshot_acquire"); + // Do not hold WM lock when calling to render thread. + final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, + height); + if (hwBitmap == null) { + return null; + } + builder.setSnapshot(hwBitmap.getHardwareBuffer()); + builder.setColorSpace(hwBitmap.getColorSpace()); + return validateSnapshot(builder.build()); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + }; } static Rect getSystemBarInsets(Rect frame, InsetsState state) { @@ -482,4 +522,45 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, pw.println(prefix + "mSnapshotEnabled=" + mSnapshotEnabled); mCache.dump(pw, prefix); } + + static class SnapshotSupplier implements Supplier<TaskSnapshot> { + + private TaskSnapshot mSnapshot; + private boolean mHasSet; + private Consumer<TaskSnapshot> mConsumer; + private Supplier<TaskSnapshot> mSupplier; + + /** Callback when the snapshot is get for the first time. */ + void setConsumer(@NonNull Consumer<TaskSnapshot> consumer) { + mConsumer = consumer; + } + + void setSupplier(@NonNull Supplier<TaskSnapshot> createSupplier) { + mSupplier = createSupplier; + } + + void setSnapshot(TaskSnapshot snapshot) { + mSnapshot = snapshot; + } + + void handleSnapshot() { + if (mHasSet) { + return; + } + mHasSet = true; + if (mSnapshot == null) { + mSnapshot = mSupplier != null ? mSupplier.get() : null; + } + if (mConsumer != null && mSnapshot != null) { + mConsumer.accept(mSnapshot); + } + } + + @Override + @Nullable + public TaskSnapshot get() { + handleSnapshot(); + return mSnapshot; + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 83b273c04648..b71256d27a14 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3227,7 +3227,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } // If the user preference respects aspect ratio, then it becomes non-resizable. - return mAppCompatController.getAppCompatOverrides().getAppCompatAspectRatioOverrides() + return mAppCompatController.getAppCompatAspectRatioOverrides() .userPreferenceCompatibleWithNonResizability(); } @@ -3898,11 +3898,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final TaskFragment taskFragment = getTaskFragment(); if (next != null && taskFragment != null && taskFragment.isEmbedded()) { final TaskFragment organized = taskFragment.getOrganizedTaskFragment(); - final TaskFragment adjacent = - organized != null ? organized.getAdjacentTaskFragment() : null; - if (adjacent != null && next.isDescendantOf(adjacent) - && organized.topRunningActivity() == null) { - delayRemoval = organized.isDelayLastActivityRemoval(); + if (Flags.allowMultipleAdjacentTaskFragments()) { + delayRemoval = organized != null + && organized.topRunningActivity() == null + && organized.isDelayLastActivityRemoval() + && organized.forOtherAdjacentTaskFragments(next::isDescendantOf); + } else { + final TaskFragment adjacent = + organized != null ? organized.getAdjacentTaskFragment() : null; + if (adjacent != null && next.isDescendantOf(adjacent) + && organized.topRunningActivity() == null) { + delayRemoval = organized.isDelayLastActivityRemoval(); + } } } @@ -4880,15 +4887,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * @see #canShowWhenLocked(ActivityRecord) */ boolean canShowWhenLocked() { + if (!canShowWhenLocked(this)) { + return false; + } final TaskFragment taskFragment = getTaskFragment(); - if (taskFragment != null && taskFragment.getAdjacentTaskFragment() != null - && taskFragment.isEmbedded()) { - final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); - final ActivityRecord r = adjacentTaskFragment.getTopNonFinishingActivity(); - return canShowWhenLocked(this) && canShowWhenLocked(r); - } else { - return canShowWhenLocked(this); + if (taskFragment == null || !taskFragment.hasAdjacentTaskFragment() + || !taskFragment.isEmbedded()) { + // No embedded adjacent that need to be checked. + return true; + } + + // Make sure the embedded adjacent can also be shown. + if (!Flags.allowMultipleAdjacentTaskFragments()) { + final ActivityRecord adjacentActivity = taskFragment.getAdjacentTaskFragment() + .getTopNonFinishingActivity(); + return canShowWhenLocked(adjacentActivity); } + final boolean hasAdjacentNotAllowToShow = taskFragment.forOtherAdjacentTaskFragments( + adjacentTF -> !canShowWhenLocked(adjacentTF.getTopNonFinishingActivity())); + return !hasAdjacentNotAllowToShow; } /** @@ -8528,8 +8545,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds // are already calculated in resolveFixedOrientationConfiguration. // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. - if (Flags.immersiveAppRepositioning() - && !mAppCompatController.getAppCompatAspectRatioPolicy() + if (!mAppCompatController.getAppCompatAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio() && !mAppCompatController.getAppCompatAspectRatioOverrides() .hasFullscreenOverride()) { @@ -8551,18 +8567,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A computeConfigByResolveHint(resolvedConfig, newParentConfiguration); } } - // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds - // are already calculated in resolveFixedOrientationConfiguration, or if in size compat - // mode, it should already be calculated in resolveSizeCompatModeConfiguration. - // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. - if (!Flags.immersiveAppRepositioning() - && !mAppCompatController.getAppCompatAspectRatioPolicy() - .isLetterboxedForFixedOrientationAndAspectRatio() - && !scmPolicy.isInSizeCompatModeForBounds() - && !mAppCompatController.getAppCompatAspectRatioOverrides() - .hasFullscreenOverride()) { - resolveAspectRatioRestriction(newParentConfiguration); - } if (isFixedOrientationLetterboxAllowed || scmPolicy.hasAppCompatDisplayInsetsWithoutInheritance() @@ -8819,9 +8823,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } boolean isImmersiveMode(@NonNull Rect parentBounds) { - if (!Flags.immersiveAppRepositioning()) { - return false; - } if (!mResolveConfigHint.mUseOverrideInsetsForConfig && mWmService.mFlags.mInsetsDecoupledConfiguration) { return false; @@ -10355,7 +10356,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (!isVisibleRequested()) { // TODO(b/294925498): Remove this finishing check once we have accurate ready tracking. - if (task != null && task.getPausingActivity() == this) { + if (task != null && task.getPausingActivity() == this + // Display is asleep, so nothing will be visible anyways. + && !mDisplayContent.isSleeping()) { // Visibility of starting activities isn't calculated until pause-complete, so if // this is not paused yet, don't consider it ready. return false; diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java index ed8b6890b2d3..597f75a52f1c 100644 --- a/services/core/java/com/android/server/wm/ActivityRefresher.java +++ b/services/core/java/com/android/server/wm/ActivityRefresher.java @@ -115,8 +115,8 @@ class ActivityRefresher { private boolean shouldRefreshActivity(@NonNull ActivityRecord activity, @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) { return mWmService.mAppCompatConfiguration.isCameraCompatRefreshEnabled() - && activity.mAppCompatController.getAppCompatOverrides() - .getAppCompatCameraOverrides().shouldRefreshActivityForCameraCompat() + && activity.mAppCompatController.getAppCompatCameraOverrides() + .shouldRefreshActivityForCameraCompat() && ArrayUtils.find(mEvaluators.toArray(), evaluator -> ((Evaluator) evaluator) .shouldRefreshActivity(activity, newConfig, lastReportedConfig)) != null; diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java index 9aaa0e1cfd6b..cfd324830db5 100644 --- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java +++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java @@ -38,6 +38,7 @@ import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.function.Supplier; /** * When an app token becomes invisible, we take a snapshot (bitmap) and put it into our cache. @@ -355,7 +356,9 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord final int[] mixedCode = new int[size]; if (size == 1) { final ActivityRecord singleActivity = activity.get(0); - final TaskSnapshot snapshot = recordSnapshotInner(singleActivity); + final Supplier<TaskSnapshot> supplier = recordSnapshotInner(singleActivity, + false /* allowAppTheme */, null /* inLockConsumer */); + final TaskSnapshot snapshot = supplier != null ? supplier.get() : null; if (snapshot != null) { mixedCode[0] = getSystemHashCode(singleActivity); addUserSavedFile(singleActivity.mUserId, snapshot, mixedCode); diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index 1a9d21187ddb..6709e3a72db0 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -25,6 +25,9 @@ import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION; import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES; import static android.content.Context.KEYGUARD_SERVICE; +import static android.content.Intent.ACTION_MAIN; +import static android.content.Intent.CATEGORY_HOME; +import static android.content.Intent.CATEGORY_SECONDARY_HOME; import static android.content.Intent.EXTRA_INTENT; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_TASK_ID; @@ -40,6 +43,7 @@ import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.TaskInfo; import android.app.admin.DevicePolicyManagerInternal; +import android.content.ComponentName; import android.content.Context; import android.content.IIntentSender; import android.content.Intent; @@ -67,6 +71,7 @@ import com.android.internal.app.UnlaunchableAppActivity; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult; +import com.android.window.flags.Flags; /** * A class that contains activity intercepting logic for {@link ActivityStarter#execute()} @@ -119,6 +124,11 @@ class ActivityStartInterceptor { */ TaskDisplayArea mPresumableLaunchDisplayArea; + /** + * Whether the component is specified originally in the given Intent. + */ + boolean mComponentSpecified; + ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) { this(service, supervisor, service.mContext); @@ -185,6 +195,14 @@ class ActivityStartInterceptor { return TaskFragment.fromTaskFragmentToken(taskFragToken, mService); } + // TODO: consolidate this method with the one below since this is used for test only. + boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, + Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, + ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) { + return intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment, callingPid, + callingUid, activityOptions, presumableLaunchDisplayArea, false); + } + /** * Intercept the launch intent based on various signals. If an interception happened the * internal variables get assigned and need to be read explicitly by the caller. @@ -193,7 +211,8 @@ class ActivityStartInterceptor { */ boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, - ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) { + ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea, + boolean componentSpecified) { mUserManager = UserManager.get(mServiceContext); mIntent = intent; @@ -206,6 +225,7 @@ class ActivityStartInterceptor { mInTaskFragment = inTaskFragment; mActivityOptions = activityOptions; mPresumableLaunchDisplayArea = presumableLaunchDisplayArea; + mComponentSpecified = componentSpecified; if (interceptQuietProfileIfNeeded()) { // If work profile is turned off, skip the work challenge since the profile can only @@ -230,7 +250,8 @@ class ActivityStartInterceptor { } if (interceptHomeIfNeeded()) { // Replace primary home intents directed at displays that do not support primary home - // but support secondary home with the relevant secondary home activity. + // but support secondary home with the relevant secondary home activity. Or the home + // intent is not in the correct format. return true; } @@ -479,9 +500,78 @@ class ActivityStartInterceptor { if (mPresumableLaunchDisplayArea == null || mService.mRootWindowContainer == null) { return false; } - if (!ActivityRecord.isHomeIntent(mIntent)) { - return false; + + boolean intercepted = false; + if (Flags.normalizeHomeIntent()) { + if (!ACTION_MAIN.equals(mIntent.getAction()) || (!mIntent.hasCategory(CATEGORY_HOME) + && !mIntent.hasCategory(CATEGORY_SECONDARY_HOME))) { + // not a home intent + return false; + } + + if (mComponentSpecified) { + final ComponentName homeComponent = mIntent.getComponent(); + final Intent homeIntent = mService.getHomeIntent(); + final ActivityInfo aInfo = mService.mRootWindowContainer.resolveHomeActivity( + mUserId, homeIntent); + if (!aInfo.getComponentName().equals(homeComponent)) { + // Do nothing if the intent is not for the default home component. + return false; + } + } + + if (!ActivityRecord.isHomeIntent(mIntent) || mComponentSpecified) { + // This is not a standard home intent, make it so if possible. + normalizeHomeIntent(); + intercepted = true; + } + } else { + if (!ActivityRecord.isHomeIntent(mIntent)) { + return false; + } + } + + intercepted |= replaceToSecondaryHomeIntentIfNeeded(); + if (intercepted) { + mCallingPid = mRealCallingPid; + mCallingUid = mRealCallingUid; + mResolvedType = null; + + mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0, + mRealCallingUid, mRealCallingPid); + mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ + null); + } + return intercepted; + } + + private void normalizeHomeIntent() { + Slog.w(TAG, "The home Intent is not correctly formatted"); + if (mIntent.getCategories().size() > 1) { + Slog.d(TAG, "Purge home intent categories"); + boolean isSecondaryHome = false; + final Object[] categories = mIntent.getCategories().toArray(); + for (int i = categories.length - 1; i >= 0; i--) { + final String category = (String) categories[i]; + if (CATEGORY_SECONDARY_HOME.equals(category)) { + isSecondaryHome = true; + } + mIntent.removeCategory(category); + } + mIntent.addCategory(isSecondaryHome ? CATEGORY_SECONDARY_HOME : CATEGORY_HOME); + } + if (mIntent.getType() != null || mIntent.getData() != null) { + Slog.d(TAG, "Purge home intent data/type"); + mIntent.setType(null); } + if (mComponentSpecified) { + Slog.d(TAG, "Purge home intent component, " + mIntent.getComponent()); + mIntent.setComponent(null); + } + mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); + } + + private boolean replaceToSecondaryHomeIntentIfNeeded() { if (!mIntent.hasCategory(Intent.CATEGORY_HOME)) { // Already a secondary home intent, leave it alone. return false; @@ -506,13 +596,6 @@ class ActivityStartInterceptor { // and should not be moved to the caller's task. Also, activities cannot change their type, // e.g. a standard activity cannot become a home activity. mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); - mCallingPid = mRealCallingPid; - mCallingUid = mRealCallingUid; - mResolvedType = null; - - mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0, - mRealCallingUid, mRealCallingPid); - mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ null); return true; } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index acb93844c945..0ab2ffe3e298 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1341,7 +1341,8 @@ class ActivityStarter { callingPackage, callingFeatureId); if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment, - callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) { + callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea, + request.componentSpecified)) { // activity start was intercepted, e.g. because the target user is currently in quiet // mode (turn off work) or the target application is suspended intent = mInterceptor.mIntent; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 5eee8ece6a67..290f155bb4cd 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -314,6 +314,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; /** * System service for managing activities and their containers (task, displays,... ). @@ -4038,6 +4039,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeTaskSnapshot()"); final long ident = Binder.clearCallingIdentity(); try { + final Supplier<TaskSnapshot> supplier; synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); @@ -4050,11 +4052,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // be retrieved by recents. While if updateCache is false, the real snapshot will // always be taken and the snapshot won't be put into SnapshotPersister. if (updateCache) { - return mWindowManager.mTaskSnapshotController.recordSnapshot(task); + supplier = mWindowManager.mTaskSnapshotController + .getRecordSnapshotSupplier(task); } else { return mWindowManager.mTaskSnapshotController.snapshot(task); } } + return supplier != null ? supplier.get() : null; } finally { Binder.restoreCallingIdentity(ident); } @@ -6403,6 +6407,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean shuttingDown(boolean booted, int timeout) { mShuttingDown = true; + mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); synchronized (mGlobalLock) { mRootWindowContainer.prepareForShutdown(); updateEventDispatchingLocked(booted); diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java index e8eae4f96a04..6a0de98c0ffa 100644 --- a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN; import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE; @@ -36,6 +37,8 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; +import com.android.window.flags.Flags; + /** * Encapsulate app compat policy logic related to aspect ratio. */ @@ -239,7 +242,14 @@ class AppCompatAspectRatioPolicy { || AppCompatUtils.isInVrUiMode(mActivityRecord.getConfiguration()) // TODO(b/232898850): Always respect aspect ratio requests. // Don't set aspect ratio for activity in ActivityEmbedding split. - || (organizedTf != null && !organizedTf.fillsParent())) { + || (organizedTf != null && !organizedTf.fillsParent()) + // Don't set aspect ratio for resizeable activities in freeform. + // {@link ActivityRecord#shouldCreateAppCompatDisplayInsets()} will be false for + // both activities that are naturally resizeable and activities that have been + // forced resizeable. + || (Flags.ignoreAspectRatioRestrictionsForResizeableFreeformActivities() + && task.getWindowingMode() == WINDOWING_MODE_FREEFORM + && !mActivityRecord.shouldCreateAppCompatDisplayInsets())) { return false; } diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java index 330283fb9ab3..4433d64f0d00 100644 --- a/services/core/java/com/android/server/wm/AppCompatController.java +++ b/services/core/java/com/android/server/wm/AppCompatController.java @@ -123,11 +123,6 @@ class AppCompatController { } @NonNull - AppCompatOverrides getAppCompatOverrides() { - return mAppCompatOverrides; - } - - @NonNull AppCompatOrientationOverrides getAppCompatOrientationOverrides() { return mAppCompatOverrides.getAppCompatOrientationOverrides(); } diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java index 4e390df14131..e929fb414340 100644 --- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java @@ -281,7 +281,6 @@ class AppCompatLetterboxPolicy { mActivityRecord.mWmService.mTransactionFactory, reachabilityPolicy, letterboxOverrides, this::getLetterboxParentSurface); - mLetterbox.attachInput(w); mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() .setLetterboxInnerBoundsSupplier(mLetterbox::getInnerFrame); } @@ -335,7 +334,7 @@ class AppCompatLetterboxPolicy { } start(winHint); if (isRunning() && mLetterbox.needsApplySurfaceChanges()) { - mLetterbox.applySurfaceChanges(t, inputT); + mLetterbox.applySurfaceChanges(t, inputT, winHint); } } diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java b/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java index caff96ba4a9f..4fac81b06680 100644 --- a/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java @@ -35,8 +35,6 @@ import android.annotation.NonNull; import android.content.res.Configuration; import android.graphics.Rect; -import com.android.window.flags.Flags; - /** * Encapsulate overrides and configurations about app compat reachability. */ @@ -157,33 +155,27 @@ class AppCompatReachabilityOverrides { } /** - * @return {@value true} if the vertical reachability should be allowed in case of + * @return {@code true} if the vertical reachability should be allowed in case of * thin letterboxing. */ boolean allowVerticalReachabilityForThinLetterbox() { - if (!Flags.disableThinLetterboxingPolicy()) { - return true; - } // When the flag is enabled we allow vertical reachability only if the // app is not thin letterboxed vertically. return !isVerticalThinLetterboxed(); } /** - * @return {@value true} if the horizontal reachability should be enabled in case of + * @return {@code true} if the horizontal reachability should be enabled in case of * thin letterboxing. */ boolean allowHorizontalReachabilityForThinLetterbox() { - if (!Flags.disableThinLetterboxingPolicy()) { - return true; - } // When the flag is enabled we allow horizontal reachability only if the // app is not thin pillarboxed. return !isHorizontalThinLetterboxed(); } /** - * @return {@value true} if the resulting app is letterboxed in a way defined as thin. + * @return {@code true} if the resulting app is letterboxed in a way defined as thin. */ boolean isVerticalThinLetterboxed() { final int thinHeight = mAppCompatConfiguration.getThinLetterboxHeightPx(); @@ -200,7 +192,7 @@ class AppCompatReachabilityOverrides { } /** - * @return {@value true} if the resulting app is pillarboxed in a way defined as thin. + * @return {@code true} if the resulting app is pillarboxed in a way defined as thin. */ boolean isHorizontalThinLetterboxed() { final int thinWidth = mAppCompatConfiguration.getThinLetterboxWidthPx(); diff --git a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java index f3b043bb51dd..d278dc3d1be7 100644 --- a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java @@ -28,8 +28,6 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; -import com.android.window.flags.Flags; - import java.io.PrintWriter; import java.util.function.DoubleSupplier; @@ -202,9 +200,7 @@ class AppCompatSizeCompatModePolicy { // saved here before resolved bounds are overridden below. final AppCompatAspectRatioPolicy aspectRatioPolicy = mActivityRecord.mAppCompatController .getAppCompatAspectRatioPolicy(); - final boolean useResolvedBounds = Flags.immersiveAppRepositioning() - ? aspectRatioPolicy.isAspectRatioApplied() - : aspectRatioPolicy.isLetterboxedForFixedOrientationAndAspectRatio(); + final boolean useResolvedBounds = aspectRatioPolicy.isAspectRatioApplied(); final Rect containerBounds = useResolvedBounds ? new Rect(resolvedBounds) : newParentConfiguration.windowConfiguration.getBounds(); diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java index 0369a0ff4c76..9f88bc952351 100644 --- a/services/core/java/com/android/server/wm/AppCompatUtils.java +++ b/services/core/java/com/android/server/wm/AppCompatUtils.java @@ -164,15 +164,13 @@ final class AppCompatUtils { appCompatTaskInfo.setIsFromLetterboxDoubleTap(reachabilityOverrides.isFromDoubleTap()); + appCompatTaskInfo.topActivityAppBounds.set(getAppBounds(top)); final boolean isTopActivityLetterboxed = top.areBoundsLetterboxed(); appCompatTaskInfo.setTopActivityLetterboxed(isTopActivityLetterboxed); if (isTopActivityLetterboxed) { final Rect bounds = top.getBounds(); - final Rect appBounds = getAppBounds(top); appCompatTaskInfo.topActivityLetterboxWidth = bounds.width(); appCompatTaskInfo.topActivityLetterboxHeight = bounds.height(); - appCompatTaskInfo.topActivityLetterboxAppWidth = appBounds.width(); - appCompatTaskInfo.topActivityLetterboxAppHeight = appBounds.height(); // TODO(b/379824541) Remove duplicate information. appCompatTaskInfo.topActivityLetterboxBounds = bounds; // We need to consider if letterboxed or pillarboxed. @@ -281,8 +279,7 @@ final class AppCompatUtils { info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET; - info.topActivityLetterboxAppHeight = TaskInfo.PROPERTY_VALUE_UNSET; - info.topActivityLetterboxAppWidth = TaskInfo.PROPERTY_VALUE_UNSET; + info.topActivityAppBounds.setEmpty(); info.topActivityLetterboxBounds = null; info.cameraCompatTaskInfo.freeformCameraCompatMode = CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_UNSPECIFIED; diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java index dd1af0a497ca..6b6f0111305c 100644 --- a/services/core/java/com/android/server/wm/AsyncRotationController.java +++ b/services/core/java/com/android/server/wm/AsyncRotationController.java @@ -29,9 +29,6 @@ import android.view.SurfaceControl; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; -import android.view.animation.AnimationUtils; - -import com.android.internal.R; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -687,11 +684,12 @@ class AsyncRotationController extends FadeAnimationController implements Consume @Override public Animation getFadeInAnimation() { + final Animation anim = super.getFadeInAnimation(); if (mHasScreenRotationAnimation) { // Use a shorter animation so it is easier to align with screen rotation animation. - return AnimationUtils.loadAnimation(mContext, R.anim.screen_rotate_0_enter); + anim.setDuration(getScaledDuration(SHORT_DURATION_MS)); } - return super.getFadeInAnimation(); + return anim; } @Override diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 1a7c6b70f007..fc0df645a2db 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -111,9 +111,7 @@ class BackNavigationController { } void onEmbeddedWindowGestureTransferred(@NonNull WindowState host) { - if (Flags.disallowAppProgressEmbeddedWindow()) { - mNavigationMonitor.onEmbeddedWindowGestureTransferred(host); - } + mNavigationMonitor.onEmbeddedWindowGestureTransferred(host); } /** @@ -215,7 +213,7 @@ class BackNavigationController { infoBuilder.setFocusedTaskId(currentTask.mTaskId); } boolean transferGestureToEmbedded = false; - if (Flags.disallowAppProgressEmbeddedWindow() && embeddedWindows != null) { + if (embeddedWindows != null) { for (int i = embeddedWindows.size() - 1; i >= 0; --i) { if (embeddedWindows.get(i).mGestureToEmbedded) { transferGestureToEmbedded = true; @@ -997,11 +995,9 @@ class BackNavigationController { /** * Handle the pending animation when the running transition finished, all the visibility change * has applied so ready to start pending predictive back animation. - * @param targets The final animation targets derived in transition. * @param finishedTransition The finished transition target. */ - void onTransitionFinish(ArrayList<Transition.ChangeInfo> targets, - @NonNull Transition finishedTransition) { + void onTransitionFinish(@NonNull Transition finishedTransition) { if (isMonitoringPrepareTransition(finishedTransition)) { if (mAnimationHandler.mPrepareCloseTransition == null) { clearBackAnimations(true /* cancel */); @@ -1049,14 +1045,6 @@ class BackNavigationController { return; } - // Ensure the final animation targets which hidden by transition could be visible. - for (int i = 0; i < targets.size(); i++) { - final WindowContainer wc = targets.get(i).mContainer; - if (wc.mSurfaceControl != null) { - wc.prepareSurfaces(); - } - } - // The pending builder could be cleared due to prepareSurfaces // => updateNonSystemOverlayWindowsVisibilityIfNeeded // => setForceHideNonSystemOverlayWindowIfNeeded diff --git a/services/core/java/com/android/server/wm/CameraStateMonitor.java b/services/core/java/com/android/server/wm/CameraStateMonitor.java index 3aa355869d85..00279921953d 100644 --- a/services/core/java/com/android/server/wm/CameraStateMonitor.java +++ b/services/core/java/com/android/server/wm/CameraStateMonitor.java @@ -110,8 +110,10 @@ class CameraStateMonitor { } void startListeningToCameraState() { - mCameraManager.registerAvailabilityCallback( - mWmService.mContext.getMainExecutor(), mAvailabilityCallback); + if (mCameraManager != null) { + mCameraManager.registerAvailabilityCallback( + mWmService.mContext.getMainExecutor(), mAvailabilityCallback); + } mIsRunning = true; } diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index 8eccffd8fe3b..a4e58ef923b8 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -368,6 +368,15 @@ final class ContentRecorder implements WindowContainerListener { return; } + final SurfaceControl sourceSurface = mRecordedWindowContainer.getSurfaceControl(); + if (sourceSurface == null || !sourceSurface.isValid()) { + ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, + "Content Recording: Unable to start recording for display %d since the " + + "surface is null or have been released.", + mDisplayContent.getDisplayId()); + return; + } + final int contentToRecord = mContentRecordingSession.getContentToRecord(); // TODO(b/297514518) Do not start capture if the app is in PIP, the bounds are inaccurate. @@ -395,8 +404,7 @@ final class ContentRecorder implements WindowContainerListener { mDisplayContent.getDisplayId(), mDisplayContent.getDisplayInfo().state); // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture. - mRecordedSurface = SurfaceControl.mirrorSurface( - mRecordedWindowContainer.getSurfaceControl()); + mRecordedSurface = SurfaceControl.mirrorSurface(sourceSurface); SurfaceControl.Transaction transaction = mDisplayContent.mWmService.mTransactionFactory.get() // Set the mMirroredSurface's parent to the root SurfaceControl for this diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f8086615b7d1..4dd950ba6ee9 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2908,6 +2908,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp && !mDisplayRotation.isRotatingSeamlessly()) { clearFixedRotationLaunchingApp(); } + // If there won't be a transition to notify the launch is done, then it should be ready to + // update with display orientation. E.g. a translucent activity enters pip from a task which + // contains another opaque activity. + if (mFixedRotationLaunchingApp != null && mFixedRotationLaunchingApp.isVisible() + && !mTransitionController.isCollecting() + && !mAtmService.mBackNavigationController.isMonitoringFinishTransition()) { + final Transition finishTransition = mTransitionController.mFinishingTransition; + if (finishTransition == null || !finishTransition.mParticipants.contains( + mFixedRotationLaunchingApp)) { + continueUpdateOrientationForDiffOrienLaunchingApp(); + } + } } /** diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 258a87eae196..3c60d8296577 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -289,7 +289,8 @@ class DragDropController { transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha); transaction.show(surfaceControl); displayContent.reparentToOverlay(transaction, surfaceControl); - mDragState.updateDragSurfaceLocked(true, touchX, touchY); + mDragState.updateDragSurfaceLocked(true /* keepHandling */, + displayContent.getDisplayId(), touchX, touchY); if (SHOW_LIGHT_TRANSACTIONS) { Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } @@ -483,10 +484,11 @@ class DragDropController { * Handles motion events. * @param keepHandling Whether if the drag operation is continuing or this is the last motion * event. + * @param displayId id of the display the X,Y coordinate is n. * @param newX X coordinate value in dp in the screen coordinate * @param newY Y coordinate value in dp in the screen coordinate */ - void handleMotionEvent(boolean keepHandling, float newX, float newY) { + void handleMotionEvent(boolean keepHandling, int displayId, float newX, float newY) { synchronized (mService.mGlobalLock) { if (!dragDropActiveLocked()) { // The drag has ended but the clean-up message has not been processed by @@ -495,7 +497,7 @@ class DragDropController { return; } - mDragState.updateDragSurfaceLocked(keepHandling, newX, newY); + mDragState.updateDragSurfaceLocked(keepHandling, displayId, newX, newY); } } diff --git a/services/core/java/com/android/server/wm/DragInputEventReceiver.java b/services/core/java/com/android/server/wm/DragInputEventReceiver.java index 5372d8b6e796..8f4548fa4fcb 100644 --- a/services/core/java/com/android/server/wm/DragInputEventReceiver.java +++ b/services/core/java/com/android/server/wm/DragInputEventReceiver.java @@ -22,13 +22,13 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.BUTTON_STYLUS_PRIMARY; + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.os.Looper; import android.util.Slog; import android.view.InputChannel; -import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.MotionEvent; @@ -63,6 +63,7 @@ class DragInputEventReceiver extends InputEventReceiver { return; } final MotionEvent motionEvent = (MotionEvent) event; + final int displayId = motionEvent.getDisplayId(); final float newX = motionEvent.getRawX(); final float newY = motionEvent.getRawY(); final boolean isStylusButtonDown = @@ -102,7 +103,8 @@ class DragInputEventReceiver extends InputEventReceiver { return; } - mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, newX, newY); + mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, displayId, newX, + newY); handled = true; } catch (Exception e) { Slog.e(TAG_WM, "Exception caught by drag handleMotion", e); diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 1c4e487d2e7e..3a0e41a5f9f8 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -113,8 +113,8 @@ class DragState { boolean mRelinquishDragSurfaceToDropTarget; float mAnimatedScale = 1.0f; float mOriginalAlpha; - float mOriginalX, mOriginalY; - float mCurrentX, mCurrentY; + float mOriginalDisplayX, mOriginalDisplayY; + float mCurrentDisplayX, mCurrentDisplayY; float mThumbOffsetX, mThumbOffsetY; InputInterceptor mInputInterceptor; ArrayList<WindowState> mNotifiedWindows; @@ -230,22 +230,22 @@ class DragState { if (mDragInProgress) { if (DEBUG_DRAG) Slog.d(TAG_WM, "Broadcasting DRAG_ENDED"); for (WindowState ws : mNotifiedWindows) { - float x = 0; - float y = 0; + float inWindowX = 0; + float inWindowY = 0; SurfaceControl dragSurface = null; if (!mDragResult && (ws.mSession.mPid == mPid)) { // Report unconsumed drop location back to the app that started the drag. - x = ws.translateToWindowX(mCurrentX); - y = ws.translateToWindowY(mCurrentY); + inWindowX = ws.translateToWindowX(mCurrentDisplayX); + inWindowY = ws.translateToWindowY(mCurrentDisplayY); if (relinquishDragSurfaceToDragSource()) { // If requested (and allowed), report the drag surface back to the app // starting the drag to handle the return animation dragSurface = mSurfaceControl; } } - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, x, y, - mThumbOffsetX, mThumbOffsetY, mFlags, null, null, null, dragSurface, null, - mDragResult); + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, inWindowX, + inWindowY, mThumbOffsetX, mThumbOffsetY, mFlags, null, null, null, + dragSurface, null, mDragResult); try { if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws); ws.mClient.dispatchDragEvent(event); @@ -297,70 +297,71 @@ class DragState { } /** - * Creates the drop event for this drag gesture. If `touchedWin` is null, then the drop event - * will be created for dispatching to the unhandled drag and the drag surface will be provided - * as a part of the dispatched event. + * Creates the drop event for dispatching to the unhandled drag. + * TODO(b/384841906): Update `inWindowX` and `inWindowY` to be display-coordinate. */ - private DragEvent createDropEvent(float x, float y, @Nullable WindowState touchedWin, - boolean includePrivateInfo) { - if (touchedWin != null) { - final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid()); - final DragAndDropPermissionsHandler dragAndDropPermissions; - if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0 - && mData != null) { - dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock, - mData, - mUid, - touchedWin.getOwningPackage(), - mFlags & DRAG_FLAGS_URI_PERMISSIONS, - mSourceUserId, - targetUserId); - } else { - dragAndDropPermissions = null; - } - if (mSourceUserId != targetUserId) { - if (mData != null) { - mData.fixUris(mSourceUserId); - } - } - final boolean targetInterceptsGlobalDrag = targetInterceptsGlobalDrag(touchedWin); - return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mDataDescription, mData, - /* includeDragSurface= */ targetInterceptsGlobalDrag, - /* includeDragFlags= */ targetInterceptsGlobalDrag, - dragAndDropPermissions); + private DragEvent createUnhandledDropEvent(float inWindowX, float inWindowY) { + return obtainDragEvent(DragEvent.ACTION_DROP, inWindowX, inWindowY, mDataDescription, mData, + /* includeDragSurface= */ true, + /* includeDragFlags= */ true, null /* dragAndDropPermissions */); + } + + /** + * Creates the drop event for this drag gesture. + */ + private DragEvent createDropEvent(float inWindowX, float inWindowY, WindowState touchedWin) { + final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid()); + final DragAndDropPermissionsHandler dragAndDropPermissions; + if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0 + && mData != null) { + dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock, mData, + mUid, touchedWin.getOwningPackage(), mFlags & DRAG_FLAGS_URI_PERMISSIONS, + mSourceUserId, targetUserId); } else { - return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mDataDescription, mData, - /* includeDragSurface= */ includePrivateInfo, - /* includeDragFlags= */ includePrivateInfo, - null /* dragAndDropPermissions */); + dragAndDropPermissions = null; } + if (mSourceUserId != targetUserId) { + if (mData != null) { + mData.fixUris(mSourceUserId); + } + } + final boolean targetInterceptsGlobalDrag = targetInterceptsGlobalDrag(touchedWin); + return obtainDragEvent(DragEvent.ACTION_DROP, inWindowX, inWindowY, mDataDescription, mData, + /* includeDragSurface= */ targetInterceptsGlobalDrag, + /* includeDragFlags= */ targetInterceptsGlobalDrag, dragAndDropPermissions); } /** * Notify the drop target and tells it about the data. If the drop event is not sent to the * target, invokes {@code endDragLocked} after the unhandled drag listener gets a chance to * handle the drop. + * @param inWindowX if `token` refers to a dragEvent-accepting window, `inWindowX` will be + * inside the window, else values might be invalid (0, 0). + * @param inWindowY if `token` refers to a dragEvent-accepting window, `inWindowY` will be + * inside the window, else values might be invalid (0, 0). */ - boolean reportDropWindowLock(IBinder token, float x, float y) { + boolean reportDropWindowLock(IBinder token, float inWindowX, float inWindowY) { if (mAnimator != null) { return false; } try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "DragDropController#DROP"); - return reportDropWindowLockInner(token, x, y); + return reportDropWindowLockInner(token, inWindowX, inWindowY); } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } } - private boolean reportDropWindowLockInner(IBinder token, float x, float y) { + private boolean reportDropWindowLockInner(IBinder token, float inWindowX, float inWindowY) { if (mAnimator != null) { return false; } final WindowState touchedWin = mService.mInputToWindowMap.get(token); - final DragEvent unhandledDropEvent = createDropEvent(x, y, null /* touchedWin */, - true /* includePrivateInfo */); + // TODO(b/384841906): The x, y here when sent to a window and unhandled, will still be + // relative to the window it was originally sent to. Need to update this to actually be + // display-coordinate. + final DragEvent unhandledDropEvent = createUnhandledDropEvent(inWindowX, inWindowY); if (!isWindowNotified(touchedWin)) { // Delegate to the unhandled drag listener as a first pass if (mDragDropController.notifyUnhandledDrop(unhandledDropEvent, "unhandled-drop")) { @@ -381,7 +382,7 @@ class DragState { if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DROP to " + touchedWin); final IBinder clientToken = touchedWin.mClient.asBinder(); - final DragEvent event = createDropEvent(x, y, touchedWin, false /* includePrivateInfo */); + final DragEvent event = createDropEvent(inWindowX, inWindowY, touchedWin); try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "DragDropController#dispatchDrop"); touchedWin.mClient.dispatchDragEvent(event); @@ -486,8 +487,8 @@ class DragState { */ void broadcastDragStartedLocked(final float touchX, final float touchY) { Trace.instant(TRACE_TAG_WINDOW_MANAGER, "DragDropController#DRAG_STARTED"); - mOriginalX = mCurrentX = touchX; - mOriginalY = mCurrentY = touchY; + mOriginalDisplayX = mCurrentDisplayX = touchX; + mOriginalDisplayY = mCurrentDisplayY = touchY; // Cache a base-class instance of the clip metadata so that parceling // works correctly in calling out to the apps. @@ -636,7 +637,7 @@ class DragState { if (isWindowNotified(newWin)) { return; } - sendDragStartedLocked(newWin, mCurrentX, mCurrentY, + sendDragStartedLocked(newWin, mCurrentDisplayX, mCurrentDisplayY, containsApplicationExtras(mDataDescription)); } } @@ -685,12 +686,21 @@ class DragState { mAnimator = createCancelAnimationLocked(); } - void updateDragSurfaceLocked(boolean keepHandling, float x, float y) { + /** + * Updates the position of the drag surface. + * + * @param keepHandling whether to keep handling the drag. + * @param displayId the display ID of the drag surface. + * @param displayX the x-coordinate of the drag surface in the display's coordinate frame. + * @param displayY the y-coordinate of the drag surface in the display's coordinate frame. + */ + void updateDragSurfaceLocked(boolean keepHandling, int displayId, float displayX, + float displayY) { if (mAnimator != null) { return; } - mCurrentX = x; - mCurrentY = y; + mCurrentDisplayX = displayX; + mCurrentDisplayY = displayY; if (!keepHandling) { return; @@ -700,9 +710,10 @@ class DragState { if (SHOW_LIGHT_TRANSACTIONS) { Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked"); } - mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply(); - ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl, - (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY)); + mTransaction.setPosition(mSurfaceControl, displayX - mThumbOffsetX, + displayY - mThumbOffsetY).apply(); + ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: displayId=%d, pos=(%d,%d)", mSurfaceControl, + displayId, (int) (displayX - mThumbOffsetX), (int) (displayY - mThumbOffsetY)); } /** @@ -713,6 +724,12 @@ class DragState { return mDragInProgress; } + /** + * `x` and `y` here varies between local window coordinate, relative coordinate to another + * window and local display coordinate, all depending on the `action`. Please take a look + * at the callers to determine the type. + * TODO(b/384845022): Properly document the events sent based on the event type. + */ private DragEvent obtainDragEvent(int action, float x, float y, ClipDescription description, ClipData data, boolean includeDragSurface, boolean includeDragFlags, IDragAndDropPermissions dragAndDropPermissions) { @@ -728,34 +745,34 @@ class DragState { final long duration; if (mCallingTaskIdToHide != -1) { animator = ValueAnimator.ofPropertyValuesHolder( - PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, mCurrentX, mCurrentX), - PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, mCurrentY, mCurrentY), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, mCurrentDisplayX, + mCurrentDisplayX), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, mCurrentDisplayY, + mCurrentDisplayY), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, mAnimatedScale), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0f)); duration = MIN_ANIMATION_DURATION_MS; } else { animator = ValueAnimator.ofPropertyValuesHolder( - PropertyValuesHolder.ofFloat( - ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, - mOriginalX - mThumbOffsetX), - PropertyValuesHolder.ofFloat( - ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, - mOriginalY - mThumbOffsetY), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, + mCurrentDisplayX - mThumbOffsetX, mOriginalDisplayX - mThumbOffsetX), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, + mCurrentDisplayY - mThumbOffsetY, mOriginalDisplayY - mThumbOffsetY), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, mAnimatedScale), - PropertyValuesHolder.ofFloat( - ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2)); + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, + mOriginalAlpha / 2)); - final float translateX = mOriginalX - mCurrentX; - final float translateY = mOriginalY - mCurrentY; + final float translateX = mOriginalDisplayX - mCurrentDisplayX; + final float translateY = mOriginalDisplayY - mCurrentDisplayY; // Adjust the duration to the travel distance. final double travelDistance = Math.sqrt( translateX * translateX + translateY * translateY); - final double displayDiagonal = - Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y); - duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal - * (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS)); + final double displayDiagonal = Math.sqrt( + mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y); + duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal * ( + MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS)); } final AnimationListener listener = new AnimationListener(); @@ -771,18 +788,20 @@ class DragState { private ValueAnimator createCancelAnimationLocked() { final ValueAnimator animator; if (mCallingTaskIdToHide != -1) { - animator = ValueAnimator.ofPropertyValuesHolder( - PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, mCurrentX, mCurrentX), - PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, mCurrentY, mCurrentY), + animator = ValueAnimator.ofPropertyValuesHolder( + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, mCurrentDisplayX, + mCurrentDisplayX), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, mCurrentDisplayY, + mCurrentDisplayY), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, mAnimatedScale), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0f)); } else { animator = ValueAnimator.ofPropertyValuesHolder( - PropertyValuesHolder.ofFloat( - ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX), - PropertyValuesHolder.ofFloat( - ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_X, + mCurrentDisplayX - mThumbOffsetX, mCurrentDisplayX), + PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_Y, + mCurrentDisplayY - mThumbOffsetY, mCurrentDisplayY), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, 0), PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0)); } diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java index 7af67e63f469..c60d3677319a 100644 --- a/services/core/java/com/android/server/wm/FadeAnimationController.java +++ b/services/core/java/com/android/server/wm/FadeAnimationController.java @@ -20,41 +20,51 @@ import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; import android.annotation.NonNull; -import android.content.Context; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AlphaAnimation; import android.view.animation.Animation; -import android.view.animation.AnimationUtils; +import android.view.animation.DecelerateInterpolator; import android.view.animation.Transformation; -import com.android.internal.R; - import java.io.PrintWriter; /** * An animation controller to fade-in/out for a window token. */ public class FadeAnimationController { + static final int SHORT_DURATION_MS = 200; + static final int MEDIUM_DURATION_MS = 350; + protected final DisplayContent mDisplayContent; - protected final Context mContext; public FadeAnimationController(DisplayContent displayContent) { mDisplayContent = displayContent; - mContext = displayContent.mWmService.mContext; } /** * @return a fade-in Animation. */ public Animation getFadeInAnimation() { - return AnimationUtils.loadAnimation(mContext, R.anim.fade_in); + final AlphaAnimation anim = new AlphaAnimation(0f, 1f); + anim.setDuration(getScaledDuration(MEDIUM_DURATION_MS)); + anim.setInterpolator(new DecelerateInterpolator()); + return anim; } /** * @return a fade-out Animation. */ public Animation getFadeOutAnimation() { - return AnimationUtils.loadAnimation(mContext, R.anim.fade_out); + final AlphaAnimation anim = new AlphaAnimation(1f, 0f); + anim.setDuration(getScaledDuration(SHORT_DURATION_MS)); + anim.setInterpolator(new AccelerateInterpolator()); + return anim; + } + + long getScaledDuration(int durationMs) { + return (long) (durationMs * mDisplayContent.mWmService.getWindowAnimationScaleLocked()); } /** Run the fade in/out animation for a window token. */ diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index cf145f94f787..ce8518449230 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -374,12 +374,6 @@ class InsetsStateController { void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) { addToPendingControlMaps(target, provider); notifyPendingInsetsControlChanged(); - - if (android.view.inputmethod.Flags.refactorInsetsController()) { - notifyInsetsChanged(); - mDisplayContent.updateSystemGestureExclusion(); - mDisplayContent.getDisplayPolicy().updateSystemBarAttributes(); - } } void notifySurfaceTransactionReady(InsetsSourceProvider provider, long id, boolean ready) { diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index ca47133a0674..29c0c7b2035e 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -22,6 +22,7 @@ import static android.window.TaskConstants.TASK_CHILD_LAYER_LETTERBOX_BACKGROUND import static android.window.TaskConstants.TASK_CHILD_LAYER_TASK_OVERLAY; import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; @@ -174,11 +175,12 @@ public class Letterbox { public void destroy() { mOuter.setEmpty(); mInner.setEmpty(); - + final SurfaceControl.Transaction tx = mTransactionFactory.get(); for (LetterboxSurface surface : mSurfaces) { - surface.remove(); + surface.remove(tx); } - mFullWindowSurface.remove(); + mFullWindowSurface.remove(tx); + tx.apply(); } /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */ @@ -196,30 +198,19 @@ public class Letterbox { /** Applies surface changes such as colour, window crop, position and input info. */ public void applySurfaceChanges(@NonNull SurfaceControl.Transaction t, - @NonNull SurfaceControl.Transaction inputT) { + @NonNull SurfaceControl.Transaction inputT, @NonNull WindowState windowState) { if (useFullWindowSurface()) { - mFullWindowSurface.applySurfaceChanges(t, inputT); - for (LetterboxSurface surface : mSurfaces) { - surface.remove(); + surface.remove(t); } + mFullWindowSurface.attachInput(windowState); + mFullWindowSurface.applySurfaceChanges(t, inputT); } else { + mFullWindowSurface.remove(t); for (LetterboxSurface surface : mSurfaces) { + surface.attachInput(windowState); surface.applySurfaceChanges(t, inputT); } - - mFullWindowSurface.remove(); - } - } - - /** Enables touches to slide into other neighboring surfaces. */ - void attachInput(WindowState win) { - if (useFullWindowSurface()) { - mFullWindowSurface.attachInput(win); - } else { - for (LetterboxSurface surface : mSurfaces) { - surface.attachInput(win); - } } } @@ -358,9 +349,10 @@ public class Letterbox { private final Rect mLayoutFrameGlobal = new Rect(); private final Rect mLayoutFrameRelative = new Rect(); + @Nullable private InputInterceptor mInputInterceptor; - public LetterboxSurface(String type) { + LetterboxSurface(@NonNull String type) { mType = type; } @@ -394,28 +386,28 @@ public class Letterbox { t.setLayer(mInputSurface, TASK_CHILD_LAYER_TASK_OVERLAY); } - void attachInput(WindowState win) { - if (mInputInterceptor != null) { - mInputInterceptor.dispose(); + void attachInput(@NonNull WindowState windowState) { + if (mInputInterceptor != null || windowState.mDisplayContent == null) { + return; } // TODO(b/371179559): only detect double tap on LB surfaces not used for cutout area. // Potentially, the input interceptor may still be needed for slippery feature. - mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win); + mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", windowState); } - public void remove() { - if (mSurface != null) { - mTransactionFactory.get().remove(mSurface).apply(); - mSurface = null; - } - if (mInputSurface != null) { - mTransactionFactory.get().remove(mInputSurface).apply(); - mInputSurface = null; - } + void remove(@NonNull SurfaceControl.Transaction t) { if (mInputInterceptor != null) { mInputInterceptor.dispose(); mInputInterceptor = null; } + if (mSurface != null) { + t.remove(mSurface); + } + if (mInputSurface != null) { + t.remove(mInputSurface); + } + mInputSurface = null; + mSurface = null; } public int getWidth() { diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index 98521d36ad44..dede7676a4b6 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -21,6 +21,7 @@ jiamingliu@google.com pdwilliams@google.com charlesccchen@google.com marziana@google.com +mcarli@google.com # Files related to background activity launches per-file Background*Start* = set noparent diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 7fdc2c67b5ce..44f000da3d73 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -1515,9 +1515,9 @@ class RecentTasks { boolean skipExcludedCheck) { if (!skipExcludedCheck) { // Keep the most recent task of home display even if it is excluded from recents. - final boolean isExcludeFromRecents = - (task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; + final boolean isExcludeFromRecents = task.getBaseIntent() != null + && (task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; if (isExcludeFromRecents) { if (DEBUG_RECENTS_TRIM_TASKS) { Slog.d(TAG, diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 3d2868540334..4f36476c674f 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1941,7 +1941,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (Flags.enableTopVisibleRootTaskPerUserTracking()) { final IntArray visibleRootTasks = new IntArray(); forAllRootTasks(rootTask -> { - if (mCurrentUser == rootTask.mUserId && rootTask.isVisibleRequested()) { + if ((mCurrentUser == rootTask.mUserId || rootTask.showForAllUsers()) + && rootTask.isVisible()) { visibleRootTasks.add(rootTask.getRootTaskId()); } }, /* traverseTopToBottom */ false); @@ -2045,6 +2046,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (Flags.enableTopVisibleRootTaskPerUserTracking()) { final IntArray rootTasks = mUserVisibleRootTasks.get(userId, new IntArray()); + // If root task already exists in the list, move it to the top instead. + final int rootTaskIndex = rootTasks.indexOf(rootTask.getRootTaskId()); + if (rootTaskIndex != -1) { + rootTasks.remove(rootTaskIndex); + } rootTasks.add(rootTask.getRootTaskId()); mUserVisibleRootTasks.put(userId, rootTasks); } else { @@ -2926,7 +2932,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void prepareForShutdown() { - mWindowManager.mSnapshotController.mTaskSnapshotController.prepareShutdown(); for (int i = 0; i < getChildCount(); i++) { createSleepToken("shutdown", getChildAt(i).mDisplayId); } diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java index 38e011509885..efc68aac0323 100644 --- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java +++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java @@ -95,8 +95,9 @@ public class ScreenRecordingCallbackController { if (mediaProjectionInfo.getLaunchCookie() == null) { mRecordedWC = (WindowContainer) mWms.mRoot.getDefaultDisplay(); } else { - mRecordedWC = mWms.mRoot.getActivity(activity -> activity.mLaunchCookie - == mediaProjectionInfo.getLaunchCookie().binder).getTask(); + final ActivityRecord matchingActivity = mWms.mRoot.getActivity(activity -> + activity.mLaunchCookie == mediaProjectionInfo.getLaunchCookie().binder); + mRecordedWC = matchingActivity != null ? matchingActivity.getTask() : null; } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 76d8861022bb..d92301ba4f6f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3652,14 +3652,6 @@ class Task extends TaskFragment { // If the developer has persist a different configuration, we need to override it to the // starting window because persisted configuration does not effect to Task. info.taskInfo.configuration.setTo(activity.getConfiguration()); - if (!Flags.drawSnapshotAspectRatioMatch()) { - final WindowState mainWindow = getTopFullscreenMainWindow(); - if (mainWindow != null) { - info.topOpaqueWindowInsetsState = - mainWindow.getInsetsStateWithVisibilityOverride(); - info.topOpaqueWindowLayoutParams = mainWindow.getAttrs(); - } - } return info; } @@ -3715,10 +3707,21 @@ class Task extends TaskFragment { // Boost the adjacent TaskFragment for dimmer if needed. final TaskFragment taskFragment = wc.asTaskFragment(); - if (taskFragment != null && taskFragment.isEmbedded()) { - final TaskFragment adjacentTf = taskFragment.getAdjacentTaskFragment(); - if (adjacentTf != null && adjacentTf.shouldBoostDimmer()) { - adjacentTf.assignLayer(t, layer++); + if (taskFragment != null && taskFragment.isEmbedded() + && taskFragment.hasAdjacentTaskFragment()) { + if (Flags.allowMultipleAdjacentTaskFragments()) { + final int[] nextLayer = { layer }; + taskFragment.forOtherAdjacentTaskFragments(adjacentTf -> { + if (adjacentTf.shouldBoostDimmer()) { + adjacentTf.assignLayer(t, nextLayer[0]++); + } + }); + layer = nextLayer[0]; + } else { + final TaskFragment adjacentTf = taskFragment.getAdjacentTaskFragment(); + if (adjacentTf.shouldBoostDimmer()) { + adjacentTf.assignLayer(t, layer++); + } } } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 9564c5959d98..3d0b41ba3a0f 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1045,7 +1045,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { + adjacentFlagRootTask); } - if (adjacentFlagRootTask.getAdjacentTaskFragment() == null) { + if (!adjacentFlagRootTask.hasAdjacentTaskFragment()) { throw new UnsupportedOperationException( "Can't set non-adjacent root as launch adjacent flag root tr=" + adjacentFlagRootTask); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 38a2ebeba332..7d300e98f44b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -36,7 +36,9 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; +import com.android.window.flags.Flags; +import java.util.ArrayList; import java.util.Set; /** @@ -154,6 +156,8 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot * The attributes of task snapshot are based on task configuration. But sometimes the * configuration may have been changed during a transition, so supply the ChangeInfo that * stored the previous appearance of the closing task. + * + * The snapshot won't be created immediately if it should be captured as fake snapshot. */ void recordSnapshot(Task task, Transition.ChangeInfo changeInfo) { mCurrentChangeInfo = changeInfo; @@ -164,13 +168,35 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot } } - TaskSnapshot recordSnapshot(Task task) { - final TaskSnapshot snapshot = recordSnapshotInner(task); - if (snapshot != null && !task.isActivityTypeHome()) { - mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); - task.onSnapshotChanged(snapshot); + void recordSnapshot(Task task) { + if (shouldDisableSnapshots()) { + return; + } + final SnapshotSupplier supplier = getRecordSnapshotSupplier(task); + if (supplier == null) { + return; } - return snapshot; + final int mode = getSnapshotMode(task); + if (Flags.excludeDrawingAppThemeSnapshotFromLock() && mode == SNAPSHOT_MODE_APP_THEME) { + mService.mH.post(supplier::handleSnapshot); + } else { + supplier.handleSnapshot(); + } + } + + /** + * Note that the snapshot is not created immediately, if the returned supplier is non-null, the + * caller must call {@link AbsAppSnapshotController.SnapshotSupplier#get} or + * {@link AbsAppSnapshotController.SnapshotSupplier#handleSnapshot} to complete the entire + * record request. + */ + SnapshotSupplier getRecordSnapshotSupplier(Task task) { + return recordSnapshotInner(task, true /* allowAppTheme */, snapshot -> { + if (!task.isActivityTypeHome()) { + mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); + task.onSnapshotChanged(snapshot); + } + }); } /** @@ -328,27 +354,38 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot * Record task snapshots before shutdown. */ void prepareShutdown() { - if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) { + if (!Flags.recordTaskSnapshotsBeforeShutdown()) { return; } - // Make write items run in a batch. - mPersister.mSnapshotPersistQueue.setPaused(true); - mPersister.mSnapshotPersistQueue.prepareShutdown(); - for (int i = 0; i < mService.mRoot.getChildCount(); i++) { - mService.mRoot.getChildAt(i).forAllLeafTasks(task -> { - if (task.isVisible() && !task.isActivityTypeHome()) { - final TaskSnapshot snapshot = captureSnapshot(task); - if (snapshot != null) { - mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); + final ArrayList<SnapshotSupplier> supplierArrayList = new ArrayList<>(); + synchronized (mService.mGlobalLock) { + // Make write items run in a batch. + mPersister.mSnapshotPersistQueue.setPaused(true); + mPersister.mSnapshotPersistQueue.prepareShutdown(); + for (int i = 0; i < mService.mRoot.getChildCount(); i++) { + mService.mRoot.getChildAt(i).forAllLeafTasks(task -> { + if (task.isVisible() && !task.isActivityTypeHome()) { + final SnapshotSupplier supplier = captureSnapshot(task, + true /* allowAppTheme */); + if (supplier != null) { + supplier.setConsumer(t -> + mPersister.persistSnapshot(task.mTaskId, task.mUserId, t)); + supplierArrayList.add(supplier); + } } - } - }, true /* traverseTopToBottom */); + }, true /* traverseTopToBottom */); + } + } + for (int i = supplierArrayList.size() - 1; i >= 0; --i) { + supplierArrayList.get(i).handleSnapshot(); + } + synchronized (mService.mGlobalLock) { + mPersister.mSnapshotPersistQueue.setPaused(false); } - mPersister.mSnapshotPersistQueue.setPaused(false); } void waitFlush(long timeout) { - if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) { + if (!Flags.recordTaskSnapshotsBeforeShutdown()) { return; } mPersister.mSnapshotPersistQueue.waitFlush(timeout); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 1f539a129e7d..a3d71dbc5ed1 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1589,7 +1589,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { cleanUpInternal(); // Handle back animation if it's already started. - mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this); + mController.mAtm.mBackNavigationController.onTransitionFinish(this); mController.mFinishingTransition = null; mController.mSnapshotController.onTransitionFinish(mType, mTargets); // Resume snapshot persist thread after snapshot controller analysis this transition. @@ -2542,15 +2542,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // TaskFragment doesn't contain occluded ActivityRecord. return true; } - final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); - if (adjacentTaskFragment != null) { - // When the TaskFragment has an adjacent TaskFragment, sibling behind them should be - // hidden unless any of them are translucent. - return adjacentTaskFragment.isTranslucentForTransition(); - } else { + if (!taskFragment.hasAdjacentTaskFragment()) { // Non-filling without adjacent is considered as translucent. return !wc.fillsParent(); } + // When the TaskFragment has an adjacent TaskFragment, sibling behind them should be + // hidden unless any of them are translucent. + if (!Flags.allowMultipleAdjacentTaskFragments()) { + return taskFragment.getAdjacentTaskFragment().isTranslucentForTransition(); + } + return taskFragment.forOtherAdjacentTaskFragments(TaskFragment::isTranslucentForTransition); } private void updatePriorVisibility() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9d9c53dfe0f4..04650b9e0150 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2945,7 +2945,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { if (callingPid != MY_PID) { - throw new WindowManager.InvalidDisplayException( + throw new IllegalArgumentException( "attachWindowContextToDisplayContent: trying to attach to a" + " non-existing display:" + displayId); } @@ -10084,14 +10084,16 @@ public class WindowManagerService extends IWindowManager.Stub TaskSnapshot taskSnapshot; final long token = Binder.clearCallingIdentity(); try { + final Supplier<TaskSnapshot> supplier; synchronized (mGlobalLock) { Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); if (task == null) { throw new IllegalArgumentException( "Failed to find matching task for taskId=" + taskId); } - taskSnapshot = mTaskSnapshotController.captureSnapshot(task); + supplier = mTaskSnapshotController.captureSnapshot(task, true /* allowAppTheme */); } + taskSnapshot = supplier != null ? supplier.get() : null; } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 01639cc3b516..d26539c377a9 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -80,6 +80,7 @@ cc_library_static { ":lib_oomConnection_native", ":lib_anrTimer_native", ":lib_lazilyRegisteredServices_native", + ":lib_phantomProcessList_native", ], include_dirs: [ @@ -265,3 +266,10 @@ filegroup { "com_android_server_vr_VrManagerService.cpp", ], } + +filegroup { + name: "lib_phantomProcessList_native", + srcs: [ + "com_android_server_am_PhantomProcessList.cpp", + ], +} diff --git a/services/core/jni/com_android_server_am_PhantomProcessList.cpp b/services/core/jni/com_android_server_am_PhantomProcessList.cpp new file mode 100644 index 000000000000..0c5e6d85919a --- /dev/null +++ b/services/core/jni/com_android_server_am_PhantomProcessList.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <processgroup/processgroup.h> + +namespace android { +namespace { + +jstring getCgroupProcsPath(JNIEnv* env, jobject clazz, jint uid, jint pid) { + if (uid < 0) { + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "uid is negative: %d", uid); + return nullptr; + } + + std::string path; + if (!CgroupGetAttributePathForProcess("CgroupProcs", uid, pid, path)) { + path.clear(); + } + + return env->NewStringUTF(path.c_str()); +} + +const JNINativeMethod sMethods[] = { + {"nativeGetCgroupProcsPath", "(II)Ljava/lang/String;", (void*)getCgroupProcsPath}, +}; + +} // anonymous namespace + +int register_android_server_am_PhantomProcessList(JNIEnv* env) { + const char* className = "com/android/server/am/PhantomProcessList"; + return jniRegisterNativeMethods(env, className, sMethods, NELEM(sMethods)); +} + +} // namespace android
\ No newline at end of file diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 04642302ce45..2403934cbeb8 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -553,6 +553,9 @@ private: PointerIcon loadPointerIcon(JNIEnv* env, ui::LogicalDisplayId displayId, PointerIconStyle type); bool isDisplayInteractive(ui::LogicalDisplayId displayId); + // TODO(b/362719483) remove when the real topology is available + void populateFakeDisplayTopology(const std::vector<DisplayViewport>& viewports); + static inline JNIEnv* jniEnv() { return AndroidRuntime::getJNIEnv(); } }; @@ -641,6 +644,49 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO mInputManager->getChoreographer().setDisplayViewports(viewports); mInputManager->getReader().requestRefreshConfiguration( InputReaderConfiguration::Change::DISPLAY_INFO); + + // TODO(b/362719483) remove when the real topology is available + populateFakeDisplayTopology(viewports); +} + +void NativeInputManager::populateFakeDisplayTopology( + const std::vector<DisplayViewport>& viewports) { + if (!com::android::input::flags::connected_displays_cursor()) { + return; + } + + // create a fake topology assuming following order + // default-display (top-edge) -> next-display (right-edge) -> next-display (right-edge) ... + // This also adds a 100px offset on corresponding edge for better manual testing + // ┌────────┐ + // │ next ├─────────┐ + // ┌─└───────┐┤ next 2 │ ... + // │ default │└─────────┘ + // └─────────┘ + DisplayTopologyGraph displaytopology; + displaytopology.primaryDisplayId = ui::LogicalDisplayId::DEFAULT; + + // treat default display as base, in real topology it should be the primary-display + ui::LogicalDisplayId previousDisplay = ui::LogicalDisplayId::DEFAULT; + for (const auto& viewport : viewports) { + if (viewport.displayId == ui::LogicalDisplayId::DEFAULT) { + continue; + } + if (previousDisplay == ui::LogicalDisplayId::DEFAULT) { + displaytopology.graph[previousDisplay].push_back( + {viewport.displayId, DisplayTopologyPosition::TOP, 100}); + displaytopology.graph[viewport.displayId].push_back( + {previousDisplay, DisplayTopologyPosition::BOTTOM, -100}); + } else { + displaytopology.graph[previousDisplay].push_back( + {viewport.displayId, DisplayTopologyPosition::RIGHT, 100}); + displaytopology.graph[viewport.displayId].push_back( + {previousDisplay, DisplayTopologyPosition::LEFT, -100}); + } + previousDisplay = viewport.displayId; + } + + mInputManager->getChoreographer().setDisplayTopology(displaytopology); } void NativeInputManager::setDisplayTopology(JNIEnv* env, jobject topologyGraph) { diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index e3bd69c30de7..569383e71a06 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -72,6 +72,7 @@ int register_com_android_server_display_DisplayControl(JNIEnv* env); int register_com_android_server_SystemClockTime(JNIEnv* env); int register_android_server_display_smallAreaDetectionController(JNIEnv* env); int register_com_android_server_accessibility_BrailleDisplayConnection(JNIEnv* env); +int register_android_server_am_PhantomProcessList(JNIEnv* env); // Note: Consider adding new JNI entrypoints for optional services to // LazyJniRegistrar instead, and relying on lazy registration. @@ -139,5 +140,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_com_android_server_SystemClockTime(env); register_android_server_display_smallAreaDetectionController(env); register_com_android_server_accessibility_BrailleDisplayConnection(env); + register_android_server_am_PhantomProcessList(env); return JNI_VERSION_1_4; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 60130d1f97be..9ab9a8f44ed9 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -91,6 +91,7 @@ import android.server.ServerProtoEnums; import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; +import android.tracing.perfetto.InitArguments; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Dumpable; @@ -440,7 +441,7 @@ public final class SystemServer implements Dumpable { "/apex/com.android.uwb/javalib/service-uwb.jar"; private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; private static final String BLUETOOTH_APEX_SERVICE_JAR_PATH = - "/apex/com.android.btservices/javalib/service-bluetooth.jar"; + "/apex/com.android.bt/javalib/service-bluetooth.jar"; private static final String BLUETOOTH_SERVICE_CLASS = "com.android.server.bluetooth.BluetoothService"; private static final String DEVICE_LOCK_SERVICE_CLASS = @@ -792,6 +793,12 @@ public final class SystemServer implements Dumpable { private void run() { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); try { + if (android.tracing.Flags.systemServerLargePerfettoShmemBuffer()) { + // Explicitly initialize a 4 MB shmem buffer for Perfetto producers (b/382369925) + android.tracing.perfetto.Producer.init(new InitArguments( + InitArguments.PERFETTO_BACKEND_SYSTEM, 4 * 1024)); + } + t.traceBegin("InitBeforeStartServices"); // Record the process start information in sys props. @@ -3114,10 +3121,10 @@ public final class SystemServer implements Dumpable { if (com.android.ranging.flags.Flags.rangingStackEnabled()) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB) || context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_RTT) + PackageManager.FEATURE_WIFI_AWARE) || (com.android.ranging.flags.Flags.rangingCsEnabled() && context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING))) { + PackageManager.FEATURE_BLUETOOTH_LE))) { t.traceBegin("RangingService"); // TODO: b/375264320 - Remove after RELEASE_RANGING_STACK is ramped to next. try { diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index d2c91ff2ef60..232bb83fdf9f 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -286,14 +286,21 @@ class AppIdPermissionPolicy : SchemePolicy() { return@forEach } var newFlags = oldFlags + val isSystemOrInstalled = + packageState.isSystem || packageState.getUserStateOrDefault(userId).isInstalled newFlags = if ( - newFlags.hasBits(PermissionFlags.ROLE) || - newFlags.hasBits(PermissionFlags.PREGRANT) + isSystemOrInstalled && ( + newFlags.hasBits(PermissionFlags.ROLE) || + newFlags.hasBits(PermissionFlags.PREGRANT) + ) ) { newFlags or PermissionFlags.RUNTIME_GRANTED } else { - newFlags andInv PermissionFlags.RUNTIME_GRANTED + newFlags andInv ( + PermissionFlags.RUNTIME_GRANTED or PermissionFlags.ROLE or + PermissionFlags.PREGRANT + ) } newFlags = newFlags andInv USER_SETTABLE_MASK if (newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)) { diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index c31594a4bf47..fc585c9e0f96 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -16,6 +16,8 @@ package com.android.server.profcollect; +import static android.content.Intent.ACTION_BATTERY_LOW; +import static android.content.Intent.ACTION_BATTERY_OKAY; import static android.content.Intent.ACTION_SCREEN_OFF; import static android.content.Intent.ACTION_SCREEN_ON; @@ -77,6 +79,7 @@ public final class ProfcollectForwardingService extends SystemService { static boolean sVerityEnforced; static boolean sIsInteractive; static boolean sAdbActive; + static boolean sIsBatteryLow; private static IProfCollectd sIProfcollect; private static ProfcollectForwardingService sSelfService; @@ -91,7 +94,11 @@ public final class ProfcollectForwardingService extends SystemService { private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (ACTION_SCREEN_ON.equals(intent.getAction())) { + if (ACTION_BATTERY_LOW.equals(intent.getAction())) { + sIsBatteryLow = true; + } else if (ACTION_BATTERY_OKAY.equals(intent.getAction())) { + sIsBatteryLow = false; + } else if (ACTION_SCREEN_ON.equals(intent.getAction())) { Log.d(LOG_TAG, "Received broadcast that the device became interactive, was " + sIsInteractive); sIsInteractive = true; @@ -141,6 +148,8 @@ public final class ProfcollectForwardingService extends SystemService { context.getResources().getBoolean(R.bool.config_profcollectReportUploaderEnabled); final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_BATTERY_LOW); + filter.addAction(ACTION_BATTERY_OKAY); filter.addAction(ACTION_SCREEN_ON); filter.addAction(ACTION_SCREEN_OFF); filter.addAction(INTENT_UPLOAD_PROFILES); diff --git a/services/profcollect/src/com/android/server/profcollect/Utils.java b/services/profcollect/src/com/android/server/profcollect/Utils.java index b754ca1875b6..c109f5cf05b6 100644 --- a/services/profcollect/src/com/android/server/profcollect/Utils.java +++ b/services/profcollect/src/com/android/server/profcollect/Utils.java @@ -118,6 +118,7 @@ final class Utils { } return ProfcollectForwardingService.sVerityEnforced && !ProfcollectForwardingService.sAdbActive - && ProfcollectForwardingService.sIsInteractive; + && ProfcollectForwardingService.sIsInteractive + && !ProfcollectForwardingService.sIsBatteryLow; } } diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt index 12370954e9a5..8b357862dcbc 100644 --- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt @@ -72,7 +72,8 @@ class AppIdPermissionPolicyPermissionResetTest : BasePermissionPolicyTest() { } else { mockPackageState( APP_ID_1, - mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)) + mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)), + true ) } setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags) diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java index d00e2c677930..1f45792e5097 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java @@ -33,6 +33,7 @@ import android.content.Context; import android.content.Intent; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; +import android.os.BinderProxy; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -290,11 +291,15 @@ public class DisplayEventDeliveryTest { } /** - * Return true if the freezer is enabled on this platform. + * Return true if the freezer is enabled on this platform and if freezer notifications are + * supported. It is not enough to test that the freezer notification feature is enabled + * because some devices do not have the necessary kernel support. */ private boolean isAppFreezerEnabled() { try { - return mActivityManager.getService().isAppFreezerEnabled(); + return mActivityManager.getService().isAppFreezerEnabled() + && android.os.Flags.binderFrozenStateChangeCallback() + && BinderProxy.isFrozenStateChangeCallbackSupported(); } catch (Exception e) { Log.e(TAG, "isAppFreezerEnabled() failed: " + e); return false; diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index f96294ed4ca8..a9ad435762ad 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -23,12 +23,14 @@ import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT; import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE; +import static android.hardware.display.DisplayManager.SWITCHING_TYPE_NONE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_SYSTEM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY; import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY; @@ -123,6 +125,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; import android.os.UserManager; import android.os.test.FakePermissionEnforcer; import android.platform.test.flag.junit.SetFlagsRule; @@ -214,7 +217,8 @@ public class DisplayManagerServiceTest { private static final String PACKAGE_NAME = "com.android.frameworks.displayservicetests"; private static final long STANDARD_DISPLAY_EVENTS = DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; private static final long STANDARD_AND_CONNECTION_DISPLAY_EVENTS = STANDARD_DISPLAY_EVENTS @@ -222,7 +226,7 @@ public class DisplayManagerServiceTest { private static final String EVENT_DISPLAY_ADDED = "EVENT_DISPLAY_ADDED"; private static final String EVENT_DISPLAY_REMOVED = "EVENT_DISPLAY_REMOVED"; - private static final String EVENT_DISPLAY_CHANGED = "EVENT_DISPLAY_CHANGED"; + private static final String EVENT_DISPLAY_BASIC_CHANGED = "EVENT_DISPLAY_BASIC_CHANGED"; private static final String EVENT_DISPLAY_BRIGHTNESS_CHANGED = "EVENT_DISPLAY_BRIGHTNESS_CHANGED"; private static final String EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = @@ -443,8 +447,6 @@ public class DisplayManagerServiceTest { when(mContext.getResources()).thenReturn(mResources); mUserManager = Mockito.spy(mContext.getSystemService(UserManager.class)); - mPermissionEnforcer.grant(CONTROL_DISPLAY_BRIGHTNESS); - mPermissionEnforcer.grant(MODIFY_USER_PREFERRED_DISPLAY_MODE); doReturn(Context.PERMISSION_ENFORCER_SERVICE).when(mContext).getSystemServiceName( eq(PermissionEnforcer.class)); doReturn(mPermissionEnforcer).when(mContext).getSystemService( @@ -889,7 +891,6 @@ public class DisplayManagerServiceTest { FakeDisplayManagerCallback callback = registerDisplayListenerCallback( displayManager, bs, displayDevice); - // Simulate DisplayDevice change DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo(); displayDeviceInfo2.copyFrom(displayDeviceInfo); @@ -900,7 +901,8 @@ public class DisplayManagerServiceTest { Handler handler = displayManager.getDisplayHandler(); waitForIdleHandler(handler); - assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_BASIC_CHANGED, + EVENT_DISPLAY_REFRESH_RATE_CHANGED); } /** @@ -2145,7 +2147,7 @@ public class DisplayManagerServiceTest { new DisplayEventReceiver.FrameRateOverride(myUid, 30f), }); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_BASIC_CHANGED); callback.clear(); updateFrameRateOverride(displayManager, displayDevice, @@ -2154,7 +2156,7 @@ public class DisplayManagerServiceTest { new DisplayEventReceiver.FrameRateOverride(1234, 30f), }); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_BASIC_CHANGED); updateFrameRateOverride(displayManager, displayDevice, new DisplayEventReceiver.FrameRateOverride[]{ @@ -2163,7 +2165,7 @@ public class DisplayManagerServiceTest { new DisplayEventReceiver.FrameRateOverride(5678, 30f), }); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_BASIC_CHANGED); callback.clear(); updateFrameRateOverride(displayManager, displayDevice, @@ -2172,7 +2174,7 @@ public class DisplayManagerServiceTest { new DisplayEventReceiver.FrameRateOverride(5678, 30f), }); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_BASIC_CHANGED); callback.clear(); updateFrameRateOverride(displayManager, displayDevice, @@ -2180,7 +2182,7 @@ public class DisplayManagerServiceTest { new DisplayEventReceiver.FrameRateOverride(5678, 30f), }); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_BASIC_CHANGED); } /** @@ -2303,16 +2305,16 @@ public class DisplayManagerServiceTest { updateRenderFrameRate(displayManager, displayDevice, 30f); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_REFRESH_RATE_CHANGED); callback.clear(); updateRenderFrameRate(displayManager, displayDevice, 30f); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_REFRESH_RATE_CHANGED); updateRenderFrameRate(displayManager, displayDevice, 20f); waitForIdleHandler(displayManager.getDisplayHandler()); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_REFRESH_RATE_CHANGED); callback.clear(); } @@ -2575,11 +2577,11 @@ public class DisplayManagerServiceTest { new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2), new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 3)); assertEquals( - new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM), - new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM)); + new HdrConversionMode(HDR_CONVERSION_SYSTEM), + new HdrConversionMode(HDR_CONVERSION_SYSTEM)); assertNotEquals( new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2), - new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM)); + new HdrConversionMode(HDR_CONVERSION_SYSTEM)); } @Test @@ -2600,7 +2602,7 @@ public class DisplayManagerServiceTest { + "HDR_CONVERSION_SYSTEM", IllegalArgumentException.class, () -> displayManager.setHdrConversionModeInternal(new HdrConversionMode( - HdrConversionMode.HDR_CONVERSION_SYSTEM, + HDR_CONVERSION_SYSTEM, Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION))); } @@ -2677,7 +2679,7 @@ public class DisplayManagerServiceTest { displayManager.setUserDisabledHdrTypesInternal(new int [0]); displayManager.setAreUserDisabledHdrTypesAllowedInternal(true); displayManager.setHdrConversionModeInternal( - new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM)); + new HdrConversionMode(HDR_CONVERSION_SYSTEM)); assertEquals(1, mAllowedHdrOutputTypes.length); assertTrue(Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION == mAllowedHdrOutputTypes[0]); @@ -2731,7 +2733,7 @@ public class DisplayManagerServiceTest { assertTrue(logicalDisplay.getDisplayInfoLocked().isForceSdr); displayManager.setHdrConversionModeInternal( - new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM)); + new HdrConversionMode(HDR_CONVERSION_SYSTEM)); assertFalse(logicalDisplay.getDisplayInfoLocked().isForceSdr); } @@ -3359,6 +3361,7 @@ public class DisplayManagerServiceTest { @Test public void testOnUserSwitching_UpdatesBrightness() { + mPermissionEnforcer.grant(CONTROL_DISPLAY_BRIGHTNESS); DisplayManagerService displayManager = new DisplayManagerService(mContext, mShortMockedInjector); DisplayManagerInternal localService = displayManager.new LocalService(); @@ -3410,6 +3413,7 @@ public class DisplayManagerServiceTest { @Test public void testOnUserSwitching_brightnessForNewUserIsDefault() { + mPermissionEnforcer.grant(CONTROL_DISPLAY_BRIGHTNESS); DisplayManagerService displayManager = new DisplayManagerService(mContext, mShortMockedInjector); DisplayManagerInternal localService = displayManager.new LocalService(); @@ -3438,7 +3442,8 @@ public class DisplayManagerServiceTest { } @Test - public void testResolutionChangeGetsBackedUp_FeatureFlagFalse() throws Exception { + public void testResolutionChangeGetsBackedUp_FeatureFlagFalse() { + mPermissionEnforcer.grant(MODIFY_USER_PREFERRED_DISPLAY_MODE); when(mMockFlags.isResolutionBackupRestoreEnabled()).thenReturn(false); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); @@ -3464,6 +3469,7 @@ public class DisplayManagerServiceTest { @Test public void testBrightnessUpdates() { + mPermissionEnforcer.grant(CONTROL_DISPLAY_BRIGHTNESS); DisplayManagerService displayManager = new DisplayManagerService(mContext, mShortMockedInjector); DisplayManagerInternal localService = displayManager.new LocalService(); @@ -3532,6 +3538,7 @@ public class DisplayManagerServiceTest { @Test public void testResolutionChangeGetsBackedUp() throws Exception { + mPermissionEnforcer.grant(MODIFY_USER_PREFERRED_DISPLAY_MODE); when(mMockFlags.isResolutionBackupRestoreEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); @@ -3888,7 +3895,7 @@ public class DisplayManagerServiceTest { observer.onChange(false, Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY)); waitForIdleHandler(handler); - assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_BASIC_CHANGED); } @Test @@ -3910,16 +3917,310 @@ public class DisplayManagerServiceTest { waitForIdleHandler(handler); // Create a default display device - createFakeDisplayDevice(displayManager, new float[] {60f}, Display.TYPE_INTERNAL); + createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL); // Create a non-default display device - createFakeDisplayDevice(displayManager, new float[] {60f}, Display.TYPE_EXTERNAL); + createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL); Settings.Secure.putInt(mContext.getContentResolver(), MIRROR_BUILT_IN_DISPLAY, 1); final ContentObserver observer = displayManager.getSettingsObserver(); observer.onChange(false, Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY)); waitForIdleHandler(handler); - assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED); + assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_BASIC_CHANGED); + } + + @Test + public void startWifiDisplayScan_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, displayManagerBinderService::startWifiDisplayScan); + } + + @Test + public void stopWifiDisplayScan_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, displayManagerBinderService::stopWifiDisplayScan); + } + + @Test + public void connectWifiDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + () -> displayManagerBinderService.connectWifiDisplay("someAddress")); + } + + @Test + public void renameWifiDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + () -> displayManagerBinderService.renameWifiDisplay("someAddress", "someAlias")); + } + + @Test + public void forgetWifiDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + () -> displayManagerBinderService.forgetWifiDisplay("someAddress")); + } + + @Test + public void pauseWifiDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, displayManagerBinderService::pauseWifiDisplay); + } + + @Test + public void resumeWifiDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, displayManagerBinderService::resumeWifiDisplay); + } + + @Test + public void setUserDisabledHdrTypes_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setUserDisabledHdrTypes(new int[0])); + } + + @Test + public void setAreUserDisabledHdrTypesAllowed_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setAreUserDisabledHdrTypesAllowed(true)); + } + + @Test + public void requestColorMode_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService.requestColorMode( + Display.DEFAULT_DISPLAY, Display.COLOR_MODE_DEFAULT)); + } + + @Test + public void getBrightnessEvents_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.getBrightnessEvents("somePackage")); + } + + @Test + public void getAmbientBrightnessStats_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + displayManagerBinderService::getAmbientBrightnessStats); + } + + @Test + public void setBrightnessConfigurationForUser_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setBrightnessConfigurationForUser( + new BrightnessConfiguration.Builder(/* lux= */ new float[]{0, 100}, + /* nits= */ new float[]{100, 200}).build(), UserHandle.USER_SYSTEM, + "somePackage")); + } + + @Test + public void setBrightnessConfigurationForDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setBrightnessConfigurationForDisplay( + new BrightnessConfiguration.Builder(/* lux= */ new float[]{0, 100}, + /* nits= */ new float[]{100, 200}).build(), "uniqueId", + UserHandle.USER_SYSTEM, "somePackage")); + } + + @Test + public void getBrightnessConfigurationForDisplay_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.getBrightnessConfigurationForDisplay("uniqueId", + UserHandle.USER_SYSTEM)); + } + + @Test + public void getDefaultBrightnessConfiguration_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + displayManagerBinderService::getDefaultBrightnessConfiguration); + } + + @Test + public void getBrightnessInfo_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.getBrightnessInfo(Display.DEFAULT_DISPLAY)); + } + + @Test + public void setTemporaryBrightness_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setTemporaryBrightness(Display.DEFAULT_DISPLAY, 0.3f)); + } + + @Test + public void setBrightness_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, 0.3f)); + } + + @Test + public void getBrightness_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY)); + } + + @Test + public void setTemporaryAutoBrightnessAdjustment_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> + displayManagerBinderService.setTemporaryAutoBrightnessAdjustment(0.1f)); + } + + @Test + public void setUserPreferredDisplayMode_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .setUserPreferredDisplayMode(Display.DEFAULT_DISPLAY, new Display.Mode( + /* width= */ 800, /* height= */ 600, /* refreshRate= */ 60))); + } + + @Test + public void setHdrConversionMode_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .setHdrConversionMode(new HdrConversionMode(HDR_CONVERSION_SYSTEM))); + } + + @Test + public void setShouldAlwaysRespectAppRequestedMode_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .setShouldAlwaysRespectAppRequestedMode(true)); + } + + @Test + public void shouldAlwaysRespectAppRequestedMode_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, + displayManagerBinderService::shouldAlwaysRespectAppRequestedMode); + } + + @Test + public void setRefreshRateSwitchingType_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .setRefreshRateSwitchingType(SWITCHING_TYPE_NONE)); + } + + @Test + public void requestDisplayModes_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .requestDisplayModes(new Binder(), Display.DEFAULT_DISPLAY, new int[0])); + } + + @Test + public void getDozeBrightnessSensorValueToBrightness_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .getDozeBrightnessSensorValueToBrightness(Display.DEFAULT_DISPLAY)); + } + + @Test + public void getDefaultDozeBrightness_withoutPermission_shouldThrowException() { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + assertThrows(SecurityException.class, () -> displayManagerBinderService + .getDefaultDozeBrightness(Display.DEFAULT_DISPLAY)); } private void initDisplayPowerController(DisplayManagerInternal localService) { @@ -4389,8 +4690,8 @@ public class DisplayManagerServiceTest { return EVENT_DISPLAY_ADDED; case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED: return EVENT_DISPLAY_REMOVED; - case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED: - return EVENT_DISPLAY_CHANGED; + case DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED: + return EVENT_DISPLAY_BASIC_CHANGED; case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED: return EVENT_DISPLAY_BRIGHTNESS_CHANGED; case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt index 5d427139a857..c65024f8f9d5 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt @@ -26,6 +26,7 @@ import org.junit.Test import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.any +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -43,7 +44,7 @@ class DisplayTopologyCoordinatorTest { @Before fun setUp() { - displayInfo.displayId = 2 + displayInfo.displayId = Display.DEFAULT_DISPLAY displayInfo.logicalWidth = 300 displayInfo.logicalHeight = 200 displayInfo.logicalDensityDpi = 100 @@ -90,6 +91,44 @@ class DisplayTopologyCoordinatorTest { } @Test + fun updateDisplay() { + whenever(mockTopology.updateDisplay(eq(Display.DEFAULT_DISPLAY), anyFloat(), anyFloat())) + .thenReturn(true) + + coordinator.onDisplayChanged(displayInfo) + + verify(mockTopologyChangedCallback).invoke(mockTopologyCopy) + } + + @Test + fun updateDisplay_notChanged() { + whenever(mockTopology.updateDisplay(eq(Display.DEFAULT_DISPLAY), anyFloat(), anyFloat())) + .thenReturn(false) + + coordinator.onDisplayChanged(displayInfo) + + verify(mockTopologyChangedCallback, never()).invoke(any()) + } + + @Test + fun removeDisplay() { + whenever(mockTopology.removeDisplay(Display.DEFAULT_DISPLAY)).thenReturn(true) + + coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY) + + verify(mockTopologyChangedCallback).invoke(mockTopologyCopy) + } + + @Test + fun removeDisplay_notChanged() { + whenever(mockTopology.removeDisplay(Display.DEFAULT_DISPLAY)).thenReturn(false) + + coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY) + + verify(mockTopologyChangedCallback, never()).invoke(any()) + } + + @Test fun getTopology_copy() { assertThat(coordinator.topology).isEqualTo(mockTopologyCopy) } diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java index ad30f22fe060..0dbb6ba58b3c 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -36,9 +36,9 @@ import static com.android.server.display.DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DE import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CONNECTED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED; -import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED; +import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; import static com.android.server.display.layout.Layout.Display.POSITION_REAR; import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN; import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SELECTIVE_STAY_AWAKE; @@ -1170,18 +1170,20 @@ public class LogicalDisplayMapperTest { @Test public void updateAndGetMaskForDisplayPropertyChanges_getsPropertyChangedFlags() { - // Change the display state + // Change the refresh rate override DisplayInfo newDisplayInfo = new DisplayInfo(); - newDisplayInfo.state = STATE_OFF; - assertEquals(LOGICAL_DISPLAY_EVENT_STATE_CHANGED, + newDisplayInfo.refreshRateOverride = 30; + assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED, mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo)); - // Change the refresh rate override + // Change the display state + when(mFlagsMock.isDisplayListenerPerformanceImprovementsEnabled()).thenReturn(true); newDisplayInfo = new DisplayInfo(); - newDisplayInfo.refreshRateOverride = 30; - assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED, + newDisplayInfo.state = STATE_OFF; + assertEquals(LOGICAL_DISPLAY_EVENT_STATE_CHANGED, mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo)); + // Change multiple properties newDisplayInfo = new DisplayInfo(); newDisplayInfo.refreshRateOverride = 30; diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp index 94d4b9522d60..03bd73c52083 100644 --- a/services/tests/mockingservicestests/jni/Android.bp +++ b/services/tests/mockingservicestests/jni/Android.bp @@ -24,6 +24,7 @@ cc_library_shared { ":lib_freezer_native", ":lib_oomConnection_native", ":lib_lazilyRegisteredServices_native", + ":lib_phantomProcessList_native", "onload.cpp", ], diff --git a/services/tests/mockingservicestests/jni/onload.cpp b/services/tests/mockingservicestests/jni/onload.cpp index 9b4c8178b092..30fa7de94af1 100644 --- a/services/tests/mockingservicestests/jni/onload.cpp +++ b/services/tests/mockingservicestests/jni/onload.cpp @@ -28,6 +28,7 @@ int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_Freezer(JNIEnv* env); int register_android_server_am_OomConnection(JNIEnv* env); int register_android_server_utils_LazyJniRegistrar(JNIEnv* env); +int register_android_server_am_PhantomProcessList(JNIEnv* env); }; using namespace android; @@ -46,5 +47,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_am_Freezer(env); register_android_server_am_OomConnection(env); register_android_server_utils_LazyJniRegistrar(env); + register_android_server_am_PhantomProcessList(env); return JNI_VERSION_1_4; } diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index 35f421e582d8..de6f9bd7527a 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -78,12 +78,15 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.SetFlagsRule; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.power.hint.HintManagerService.AppHintSession; import com.android.server.power.hint.HintManagerService.Injector; import com.android.server.power.hint.HintManagerService.NativeWrapper; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -93,6 +96,8 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; @@ -111,6 +116,7 @@ import java.util.concurrent.locks.LockSupport; */ public class HintManagerServiceTest { private static final String TAG = "HintManagerServiceTest"; + private List<File> mFilesCreated = new ArrayList<>(); private static WorkDuration makeWorkDuration( long timestamp, long duration, long workPeriodStartTime, @@ -192,9 +198,9 @@ public class HintManagerServiceTest { mSupportInfo.sessionTags = -1; mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); mSupportInfo.headroom.isCpuSupported = true; - mSupportInfo.headroom.cpuMinIntervalMillis = 2000; + mSupportInfo.headroom.cpuMinIntervalMillis = 1000; mSupportInfo.headroom.isGpuSupported = true; - mSupportInfo.headroom.gpuMinIntervalMillis = 2000; + mSupportInfo.headroom.gpuMinIntervalMillis = 1000; mSupportInfo.compositionData = new SupportInfo.CompositionDataSupportInfo(); return mSupportInfo; } @@ -243,6 +249,13 @@ public class HintManagerServiceTest { LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); } + @After + public void tearDown() { + for (File file : mFilesCreated) { + file.delete(); + } + } + /** * Mocks the creation calls, but without support for new createHintSessionWithConfig method */ @@ -1327,6 +1340,58 @@ public class HintManagerServiceTest { }); } + @Test + public void testCpuHeadroomCpuProcStatPath() throws Exception { + File dir = InstrumentationRegistry.getTargetContext().getFilesDir(); + dir.mkdir(); + String procStatFileStr = "mock_proc_stat"; + File file = new File(dir, procStatFileStr); + mFilesCreated.add(file); + try (FileOutputStream output = new FileOutputStream(file)) { + output.write("cpu 2000 3000 4000 0 0 0 0 0 0 0".getBytes()); + } + HintManagerService service = createService(); + service.setProcStatPathOverride(file.getPath()); + + CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal(); + CpuHeadroomParams halParams1 = new CpuHeadroomParams(); + halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN; + halParams1.tids = new int[]{Process.myPid()}; + + float headroom1 = 0.1f; + CpuHeadroomResult halRet1 = CpuHeadroomResult.globalHeadroom(headroom1); + when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(halRet1); + clearInvocations(mIPowerMock); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); + // expire the cache but cpu proc hasn't changed so we expect no value return + Thread.sleep(1100); + clearInvocations(mIPowerMock); + assertEquals(null, service.getBinderServiceInstance().getCpuHeadroom(params1)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1)); + + // update user jiffies with 500 equivalent jiffies, which is not sufficient cpu time + Thread.sleep(1100); + try (FileOutputStream output = new FileOutputStream(file)) { + output.write(("cpu " + (2000 + (int) (500 / service.mJiffyMillis)) + + " 3000 4000 0 0 0 0 0 0 0").getBytes()); + } + clearInvocations(mIPowerMock); + assertEquals(null, service.getBinderServiceInstance().getCpuHeadroom(params1)); + verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1)); + + // update nice jiffies with 600 equivalent jiffies, now it exceeds 1000ms requirement + Thread.sleep(1100); + try (FileOutputStream output = new FileOutputStream(file)) { + output.write(("cpu " + (2000 + (int) (500 / service.mJiffyMillis)) + + " " + +(3000 + (int) (600 / service.mJiffyMillis)) + + " 4000 0 0 0 0 0 0 0").getBytes()); + } + clearInvocations(mIPowerMock); + assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); + } + @Test @EnableFlags({Flags.FLAG_CPU_HEADROOM_AFFINITY_CHECK}) @@ -1397,8 +1462,8 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3)); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); - // after 1 more second it should be served with cache still - Thread.sleep(1000); + // after 500ms more it should be served with cache + Thread.sleep(500); clearInvocations(mIPowerMock); assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); @@ -1410,8 +1475,8 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3)); verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4)); - // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval - Thread.sleep(1100); + // after 1+ seconds it should be served from HAL as it exceeds 1000 millis interval + Thread.sleep(600); clearInvocations(mIPowerMock); assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1)); assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2)); @@ -1519,8 +1584,8 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); - // after 1 more second it should be served with cache still - Thread.sleep(1000); + // after 500ms it should be served with cache + Thread.sleep(500); clearInvocations(mIPowerMock); assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); @@ -1528,8 +1593,8 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); - // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval - Thread.sleep(1100); + // after 1+ seconds it should be served from HAL as it exceeds 1000 millis interval + Thread.sleep(600); clearInvocations(mIPowerMock); assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1)); assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2)); diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java index 96741e0b1e87..469bd66b7e7b 100644 --- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java @@ -21,6 +21,7 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; @@ -889,6 +890,32 @@ public class NotifierTest { "my.package.name", false, null, null); } + @Test + public void getWakelockMonitorTypeForLogging_evaluatesWakelockLevel() { + createNotifier(); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.SCREEN_DIM_WAKE_LOCK), + PowerManager.FULL_WAKE_LOCK); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK), PowerManager.FULL_WAKE_LOCK); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.DRAW_WAKE_LOCK), + PowerManager.DRAW_WAKE_LOCK); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.PARTIAL_WAKE_LOCK), + PowerManager.PARTIAL_WAKE_LOCK); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging( + PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK), + PowerManager.PARTIAL_WAKE_LOCK); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging( + PowerManager.DOZE_WAKE_LOCK), -1); + + when(mResourcesSpy.getBoolean( + com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity)) + .thenReturn(true); + + createNotifier(); + assertEquals(mNotifier.getWakelockMonitorTypeForLogging( + PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK), -1); + } + private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS index d8a9400d5180..69feb1d86983 100644 --- a/services/tests/servicestests/src/com/android/server/OWNERS +++ b/services/tests/servicestests/src/com/android/server/OWNERS @@ -6,5 +6,6 @@ per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS per-file BatteryServiceTest.java = file:platform/hardware/interfaces:/health/OWNERS per-file GestureLauncherServiceTest.java = file:platform/packages/apps/EmergencyInfo:/OWNERS +per-file GestureLauncherServiceTest.java = file:/INPUT_OWNERS per-file PinnerServiceTest.java = file:/apct-tests/perftests/OWNERS per-file SecurityStateTest.java = file:/SECURITY_STATE_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 2fe6918630f6..7dbbff22a537 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -33,6 +33,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.server.am.UserController.CLEAR_USER_JOURNEY_SESSION_MSG; import static com.android.server.am.UserController.COMPLETE_USER_SWITCH_MSG; import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG; +import static com.android.server.am.UserController.DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS; import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG; @@ -94,6 +95,7 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManagerInternal; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IStorageManager; @@ -181,14 +183,12 @@ public class UserControllerTest { Intent.ACTION_USER_STARTING); private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet( - 0, // for startUserInternalOnHandler REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG, USER_START_MSG, USER_CURRENT_MSG); private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet( - 0, // for startUserInternalOnHandler USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG); @@ -376,7 +376,7 @@ public class UserControllerTest { // and the cascade effect goes on...). In fact, a better approach would to not assert the // binder calls, but their side effects (in this case, that the user is stopped right away) assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes()) - .containsExactly(/* for startUserInternalOnHandler */ 0, USER_START_MSG); + .containsExactly(USER_START_MSG); } private void startUserAssertions( @@ -419,17 +419,12 @@ public class UserControllerTest { @Test public void testDispatchUserSwitch() throws RemoteException { // Prepare mock observer and register it - IUserSwitchObserver observer = mock(IUserSwitchObserver.class); - when(observer.asBinder()).thenReturn(new Binder()); - doAnswer(invocation -> { - IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; - callback.sendResult(null); - return null; - }).when(observer).onUserSwitching(anyInt(), any()); - mUserController.registerUserSwitchObserver(observer, "mock"); + IUserSwitchObserver observer = registerUserSwitchObserver( + /* replyToOnBeforeUserSwitchingCallback= */ true, + /* replyToOnUserSwitchingCallback= */ true); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; @@ -453,14 +448,26 @@ public class UserControllerTest { } @Test + public void testShouldCrashWhenOnBeforeUserSwitchingTimeouts() throws RemoteException { + IUserSwitchObserver observer = registerUserSwitchObserver( + /* replyToOnBeforeUserSwitchingCallback= */ false, + /* replyToOnUserSwitchingCallback= */ true); + mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); + assertThrows("Should have crashed when observers don't reply to onBeforeUserSwitching in " + + DEFAULT_BEFORE_USER_SWITCH_TIMEOUT_MS + " ms", RuntimeException.class, + mInjector.mHandler::runPendingCallbacks); + } + + @Test public void testDispatchUserSwitchBadReceiver() throws RemoteException { - // Prepare mock observer which doesn't notify the callback and register it - IUserSwitchObserver observer = mock(IUserSwitchObserver.class); - when(observer.asBinder()).thenReturn(new Binder()); - mUserController.registerUserSwitchObserver(observer, "mock"); + // Prepare mock observer which doesn't notify the onUserSwitching callback and register it + IUserSwitchObserver observer = registerUserSwitchObserver( + /* replyToOnBeforeUserSwitchingCallback= */ true, + /* replyToOnUserSwitchingCallback= */ false); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID)); + verify(observer, times(1)).onBeforeUserSwitching(eq(TEST_USER_ID), any()); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; @@ -551,7 +558,6 @@ public class UserControllerTest { expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG); if (backgroundUserStopping) { expectedCodes.add(CLEAR_USER_JOURNEY_SESSION_MSG); - expectedCodes.add(0); // this is for directly posting in stopping. } if (expectScheduleBackgroundUserStopping) { expectedCodes.add(SCHEDULED_STOP_BACKGROUND_USER_MSG); @@ -567,9 +573,9 @@ public class UserControllerTest { @Test public void testDispatchUserSwitchComplete() throws RemoteException { // Prepare mock observer and register it - IUserSwitchObserver observer = mock(IUserSwitchObserver.class); - when(observer.asBinder()).thenReturn(new Binder()); - mUserController.registerUserSwitchObserver(observer, "mock"); + IUserSwitchObserver observer = registerUserSwitchObserver( + /* replyToOnBeforeUserSwitchingCallback= */ true, + /* replyToOnUserSwitchingCallback= */ true); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); @@ -1752,6 +1758,29 @@ public class UserControllerTest { verify(mInjector, never()).onSystemUserVisibilityChanged(anyBoolean()); } + private IUserSwitchObserver registerUserSwitchObserver( + boolean replyToOnBeforeUserSwitchingCallback, boolean replyToOnUserSwitchingCallback) + throws RemoteException { + IUserSwitchObserver observer = mock(IUserSwitchObserver.class); + when(observer.asBinder()).thenReturn(new Binder()); + if (replyToOnBeforeUserSwitchingCallback) { + doAnswer(invocation -> { + IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; + callback.sendResult(null); + return null; + }).when(observer).onBeforeUserSwitching(anyInt(), any()); + } + if (replyToOnUserSwitchingCallback) { + doAnswer(invocation -> { + IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1]; + callback.sendResult(null); + return null; + }).when(observer).onUserSwitching(anyInt(), any()); + } + mUserController.registerUserSwitchObserver(observer, "mock"); + return observer; + } + // Should be public to allow mocking private static class TestInjector extends UserController.Injector { public final TestHandler mHandler; @@ -1957,6 +1986,7 @@ public class UserControllerTest { * fix this, but in the meantime, this is your warning. */ private final List<Message> mMessages = new ArrayList<>(); + private final List<Runnable> mPendingCallbacks = new ArrayList<>(); TestHandler(Looper looper) { super(looper); @@ -1989,14 +2019,24 @@ public class UserControllerTest { @Override public boolean sendMessageAtTime(Message msg, long uptimeMillis) { - Message copy = new Message(); - copy.copyFrom(msg); - mMessages.add(copy); - if (msg.getCallback() != null) { - msg.getCallback().run(); + if (msg.getCallback() == null) { + Message copy = new Message(); + copy.copyFrom(msg); + mMessages.add(copy); + } else { + if (SystemClock.uptimeMillis() >= uptimeMillis) { + msg.getCallback().run(); + } else { + mPendingCallbacks.add(msg.getCallback()); + } msg.setCallback(null); } return super.sendMessageAtTime(msg, uptimeMillis); } + + private void runPendingCallbacks() { + mPendingCallbacks.forEach(Runnable::run); + mPendingCallbacks.clear(); + } } } diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java index b1df0f1e9cce..c7a06b8eec7b 100644 --- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java @@ -31,6 +31,7 @@ import android.os.test.FakePermissionEnforcer; import android.os.test.TestLooper; import android.provider.Settings; import android.security.advancedprotection.AdvancedProtectionFeature; +import android.security.advancedprotection.AdvancedProtectionManager; import android.security.advancedprotection.IAdvancedProtectionCallback; import androidx.annotation.NonNull; @@ -54,7 +55,8 @@ public class AdvancedProtectionServiceTest { private Context mContext; private AdvancedProtectionService.AdvancedProtectionStore mStore; private TestLooper mLooper; - AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature("test-id"); + AdvancedProtectionFeature mTestFeature2g = new AdvancedProtectionFeature( + AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G); @Before public void setup() throws Settings.SettingNotFoundException { @@ -105,7 +107,7 @@ public class AdvancedProtectionServiceTest { @NonNull @Override public AdvancedProtectionFeature getFeature() { - return mFeature; + return mTestFeature2g; } @Override @@ -135,7 +137,7 @@ public class AdvancedProtectionServiceTest { @NonNull @Override public AdvancedProtectionFeature getFeature() { - return mFeature; + return mTestFeature2g; } @Override @@ -165,7 +167,7 @@ public class AdvancedProtectionServiceTest { @NonNull @Override public AdvancedProtectionFeature getFeature() { - return mFeature; + return mTestFeature2g; } @Override @@ -238,8 +240,10 @@ public class AdvancedProtectionServiceTest { @Test public void testGetFeatures() { - AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1"); - AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2"); + AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature( + AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G); + AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature( + AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES); AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) { @NonNull @Override @@ -268,8 +272,10 @@ public class AdvancedProtectionServiceTest { @Test public void testGetFeatures_featureNotAvailable() { - AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1"); - AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2"); + AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature( + AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G); + AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature( + AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES); AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) { @NonNull @Override diff --git a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java index 9c61d95bc5e5..9528a05d38a0 100644 --- a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java @@ -23,13 +23,13 @@ import android.test.AndroidTestCase; import android.util.Pair; import android.util.Xml; -import com.android.internal.util.FastXmlSerializer; import com.android.modules.utils.TypedXmlSerializer; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; import java.io.StringWriter; @@ -123,8 +123,24 @@ public class CacheQuotaStrategyTest extends AndroidTestCase { buildCacheQuotaHint("uuid2", 10, 250)); } + @Test + public void testReadInvalidInput() throws Exception { + String input = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<cache-info previousBytes=\"1000\">\n" + + "<quota/>\n" + + "</cache-info>\n"; + + try { + CacheQuotaStrategy.readFromXml(new ByteArrayInputStream( + input.getBytes("UTF-8"))); + fail("Expected XML parsing exception"); + } catch (XmlPullParserException e) { + // Expected XmlPullParserException exception + } + } + private CacheQuotaHint buildCacheQuotaHint(String volumeUuid, int uid, long quota) { return new CacheQuotaHint.Builder() .setVolumeUuid(volumeUuid).setUid(uid).setQuota(quota).build(); } -}
\ No newline at end of file +} 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 decbaacdcef9..d1dc8d6e81c8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -274,6 +274,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { assertEquals(new ArraySet<>(), approved.get(true)); } + @SuppressWarnings("GuardedBy") @Test public void testReadXml_userDisabled_restore() throws Exception { String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">" @@ -289,7 +290,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase { mAssistants.readXml(parser, mNm::canUseManagedServices, true, ActivityManager.getCurrentUser()); - ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get(0); + ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get( + ActivityManager.getCurrentUser()); // approved should not be null assertNotNull(approved); 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 20f4bb65d27b..601023f89656 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -17683,4 +17683,145 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(mService.mNotificationList).isEmpty(); } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) + public void testUnbundleNotification_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); + + // Post a single notification + final boolean hasOriginalSummary = false; + final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + final String keyToUnbundle = r.getKey(); + mService.addNotification(r); + + // Classify notification into the NEWS bundle + Bundle signals = new Bundle(); + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); + Adjustment adjustment = new Adjustment( + r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); + // Check that the Notification mChannelId is not updated + assertThat(r.getNotification().getChannelId()).isEqualTo(TEST_CHANNEL_ID); + + // Unbundle the notification + mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + + // Check that the original channel was restored + assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary)); + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) + public void testUnbundleNotification_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); + + // Post grouped notifications + final String originalGroupName = "originalGroup"; + final int summaryId = 0; + final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, + summaryId + 1, originalGroupName, false); + mService.addNotification(r1); + final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, + summaryId + 2, originalGroupName, false); + mService.addNotification(r2); + final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, + summaryId, originalGroupName, true); + mService.addNotification(summary); + final String originalGroupKey = summary.getGroupKey(); + assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); + + // Classify a child notification into the NEWS bundle + final String keyToUnbundle = r1.getKey(); + final boolean hasOriginalSummary = true; + Bundle signals = new Bundle(); + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); + Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals, + "", r1.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r1.applyAdjustments(); + assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); + + // Unbundle the notification + mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + + // Check that the original channel was restored + assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary)); + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) + public void testUnbundleNotification_groupedSummaryCanceled_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); + + // Post grouped notifications + final String originalGroupName = "originalGroup"; + final int summaryId = 0; + final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, + summaryId + 1, originalGroupName, false); + mService.addNotification(r1); + final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, + summaryId + 2, originalGroupName, false); + mService.addNotification(r2); + final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, + summaryId, originalGroupName, true); + mService.addNotification(summary); + final String originalGroupKey = summary.getGroupKey(); + assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); + + // Classify a child notification into the NEWS bundle + final String keyToUnbundle = r1.getKey(); + Bundle signals = new Bundle(); + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); + Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals, + "", r1.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r1.applyAdjustments(); + assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); + + // Cancel original summary + final boolean hasOriginalSummary = false; + mService.mSummaryByGroupKey.remove(summary.getGroupKey()); + + // Unbundle the notification + mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + + // Check that the original channel was restored + assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary)); + } + } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index fbd53f714dbf..8e79514c875e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -66,7 +66,6 @@ import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.No import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED; -import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; import static com.android.server.notification.Flags.FLAG_NOTIFICATION_VERIFY_CHANNEL_SOUND_URI; import static com.android.server.notification.Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA; import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER; @@ -155,7 +154,6 @@ import android.util.proto.ProtoOutputStream; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.internal.config.sysui.TestableFlagResolver; @@ -167,9 +165,6 @@ import com.android.os.AtomsProto.PackageNotificationPreferences; import com.android.server.UiServiceTestCase; import com.android.server.notification.PermissionHelper.PackagePermission; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.protobuf.InvalidProtocolBufferException; @@ -204,6 +199,9 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @EnableFlags(FLAG_PERSIST_INCOMPLETE_RESTORE_DATA) @@ -2640,6 +2638,35 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void getPackagesBypassingDnd_multipleUsers() { + int uidUser1 = UserHandle.getUid(1, UID_P); + NotificationChannel channelUser1Bypass = new NotificationChannel("id11", "name1", + NotificationManager.IMPORTANCE_MAX); + channelUser1Bypass.setBypassDnd(true); + NotificationChannel channelUser1NoBypass = new NotificationChannel("id12", "name2", + NotificationManager.IMPORTANCE_MAX); + channelUser1NoBypass.setBypassDnd(false); + + int uidUser2 = UserHandle.getUid(2, UID_P); + NotificationChannel channelUser2Bypass = new NotificationChannel("id21", "name1", + NotificationManager.IMPORTANCE_MAX); + channelUser2Bypass.setBypassDnd(true); + + mHelper.createNotificationChannel(PKG_P, uidUser1, channelUser1Bypass, true, + /* hasDndAccess= */ true, uidUser1, false); + mHelper.createNotificationChannel(PKG_P, uidUser1, channelUser1NoBypass, true, + /* hasDndAccess= */ true, uidUser1, false); + mHelper.createNotificationChannel(PKG_P, uidUser2, channelUser2Bypass, true, + /* hasDndAccess= */ true, uidUser2, false); + + assertThat(mHelper.getPackagesBypassingDnd(0)).isEmpty(); + assertThat(mHelper.getPackagesBypassingDnd(1)) + .containsExactly(new ZenBypassingApp(PKG_P, false)); + assertThat(mHelper.getPackagesBypassingDnd(2)) + .containsExactly(new ZenBypassingApp(PKG_P, true)); + } + + @Test public void getPackagesBypassingDnd_oneChannelBypassing_groupBlocked() { int uid = UID_N_MR1; NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java index a7fc10f2fcc5..948371f74a9c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.never; @@ -253,7 +254,11 @@ public class ActivitySnapshotControllerTests extends TaskSnapshotPersisterTestBa */ @Test public void testSkipRecordActivity() { - doReturn(createSnapshot()).when(mActivitySnapshotController).recordSnapshotInner(any()); + final AbsAppSnapshotController.SnapshotSupplier supplier = + new AbsAppSnapshotController.SnapshotSupplier(); + supplier.setSupplier(this::createSnapshot); + doReturn(supplier).when(mActivitySnapshotController).recordSnapshotInner( + any(), anyBoolean(), any()); final Task task = createTask(mDisplayContent); mSnapshotPersistQueue.setPaused(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 670f9f697a5c..bacf5ed9d81f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -53,7 +53,9 @@ import android.content.pm.UserPackage; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.DexmakerShareClassLoaderRule; import android.util.Pair; import android.util.SparseArray; @@ -66,6 +68,7 @@ import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.Before; @@ -133,6 +136,8 @@ public class ActivityStartInterceptorTest { private SparseArray<ActivityInterceptorCallback> mActivityInterceptorCallbacks = new SparseArray<>(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); @@ -237,6 +242,20 @@ public class ActivityStartInterceptorTest { } @Test + @EnableFlags(Flags.FLAG_NORMALIZE_HOME_INTENT) + public void testInterceptIncorrectHomeIntent() { + // Create a non-standard home intent + final Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + homeIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + // Ensure the intent is intercepted and normalized to standard home intent. + assertTrue(mInterceptor.intercept(homeIntent, null, mAInfo, null, null, null, 0, 0, null, + mTaskDisplayArea, false)); + assertTrue(ActivityRecord.isHomeIntent(homeIntent)); + } + + @Test public void testInterceptLockTaskModeViolationPackage() { when(mLockTaskController.isActivityAllowed( TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)) diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java index 8747cfae93f8..9d191cea8acb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java @@ -335,8 +335,7 @@ public class AppCompatOrientationOverridesTest extends WindowTestsBase { } private AppCompatOrientationOverrides getTopOrientationOverrides() { - return activity().top().mAppCompatController.getAppCompatOverrides() - .getAppCompatOrientationOverrides(); + return activity().top().mAppCompatController.getAppCompatOrientationOverrides(); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java index 90bf5f03bb1f..a21ab5de5de2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java @@ -601,8 +601,7 @@ public class AppCompatOrientationPolicyTest extends WindowTestsBase { } private AppCompatOrientationOverrides getTopOrientationOverrides() { - return activity().top().mAppCompatController.getAppCompatOverrides() - .getAppCompatOrientationOverrides(); + return activity().top().mAppCompatController.getAppCompatOrientationOverrides(); } private AppCompatOrientationPolicy getTopAppCompatOrientationPolicy() { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java index 1edbcd527bf4..463254caa845 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java @@ -23,14 +23,10 @@ import static org.mockito.Mockito.spy; import android.compat.testing.PlatformCompatChangeRule; import android.graphics.Rect; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; -import com.android.window.flags.Flags; - import junit.framework.Assert; import org.junit.Rule; @@ -125,8 +121,7 @@ public class AppCompatReachabilityOverridesTest extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY) - public void testAllowReachabilityForThinLetterboxWithFlagEnabled() { + public void testAllowReachabilityForThinLetterbox_disableForThinLetterboxing() { runTestScenario((robot) -> { robot.activity().createActivityWithComponent(); @@ -142,24 +137,6 @@ public class AppCompatReachabilityOverridesTest extends WindowTestsBase { }); } - @Test - @DisableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY) - public void testAllowReachabilityForThinLetterboxWithFlagDisabled() { - runTestScenario((robot) -> { - robot.activity().createActivityWithComponent(); - - robot.configureIsVerticalThinLetterboxed(/* isThin */ true); - robot.checkAllowVerticalReachabilityForThinLetterbox(/* expected */ true); - robot.configureIsHorizontalThinLetterboxed(/* isThin */ true); - robot.checkAllowHorizontalReachabilityForThinLetterbox(/* expected */ true); - - robot.configureIsVerticalThinLetterboxed(/* isThin */ false); - robot.checkAllowVerticalReachabilityForThinLetterbox(/* expected */ true); - robot.configureIsHorizontalThinLetterboxed(/* isThin */ false); - robot.checkAllowHorizontalReachabilityForThinLetterbox(/* expected */ true); - }); - } - /** * Runs a test scenario providing a Robot. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index 0a7df5a305bc..0af41ea1f634 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -450,7 +450,7 @@ public class DisplayAreaTest extends WindowTestsBase { public void testGetOrientation() { final DisplayArea.Tokens area = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "test"); mDisplayContent.addChild(area, POSITION_TOP); - final WindowState win = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay"); + final WindowState win = newWindowBuilder("overlay", TYPE_APPLICATION_OVERLAY).build(); win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; win.mToken.reparent(area, POSITION_TOP); spyOn(win); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index db71f2bf039d..57aacd36b16b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -178,8 +178,8 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addAllCommonWindows = true) @Test public void testForAllWindows() { - final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, - mDisplayContent, "exiting app"); + final WindowState exitingAppWindow = newWindowBuilder("exiting app", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); final ActivityRecord exitingApp = exitingAppWindow.mActivityRecord; exitingApp.startAnimation(exitingApp.getPendingTransaction(), mock(AnimationAdapter.class), false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION); @@ -211,8 +211,8 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addAllCommonWindows = true) @Test public void testForAllWindows_WithAppImeTarget() { - final WindowState imeAppTarget = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); + final WindowState imeAppTarget = newWindowBuilder("imeAppTarget", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); mDisplayContent.setImeLayeringTarget(imeAppTarget); @@ -289,8 +289,8 @@ public class DisplayContentTests extends WindowTestsBase { public void testForAllWindows_WithInBetweenWindowToken() { // This window is set-up to be z-ordered between some windows that go in the same token like // the nav bar and status bar. - final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION, - mDisplayContent, "voiceInteractionWindow"); + final WindowState voiceInteractionWindow = newWindowBuilder("voiceInteractionWindow", + TYPE_VOICE_INTERACTION).setDisplay(mDisplayContent).build(); assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -310,7 +310,8 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeTarget() { // Verify that an app window can be an ime target. - final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); + final WindowState appWin = newWindowBuilder("appWin", TYPE_APPLICATION).setDisplay( + mDisplayContent).build(); appWin.setHasSurface(true); assertTrue(appWin.canBeImeTarget()); WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); @@ -318,8 +319,8 @@ public class DisplayContentTests extends WindowTestsBase { appWin.mHidden = false; // Verify that an child window can be an ime target. - final WindowState childWin = createWindow(appWin, - TYPE_APPLICATION_ATTACHED_DIALOG, "childWin"); + final WindowState childWin = newWindowBuilder("childWin", + TYPE_APPLICATION_ATTACHED_DIALOG).setParent(appWin).build(); childWin.setHasSurface(true); assertTrue(childWin.canBeImeTarget()); imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); @@ -331,8 +332,8 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeTarget_startingWindow() { ActivityRecord activity = createActivityRecord(mDisplayContent); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "startingWin"); + final WindowState startingWin = newWindowBuilder("startingWin", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); startingWin.setHasSurface(true); assertTrue(startingWin.canBeImeTarget()); @@ -342,7 +343,8 @@ public class DisplayContentTests extends WindowTestsBase { // Verify that the starting window still be an ime target even an app window launching // behind it. - final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "appWin"); + final WindowState appWin = newWindowBuilder("appWin", TYPE_BASE_APPLICATION).setWindowToken( + activity).build(); appWin.setHasSurface(true); assertTrue(appWin.canBeImeTarget()); @@ -352,8 +354,8 @@ public class DisplayContentTests extends WindowTestsBase { // Verify that the starting window still be an ime target even the child window behind a // launching app window - final WindowState childWin = createWindow(appWin, - TYPE_APPLICATION_ATTACHED_DIALOG, "childWin"); + final WindowState childWin = newWindowBuilder("childWin", + TYPE_APPLICATION_ATTACHED_DIALOG).setParent(appWin).build(); childWin.setHasSurface(true); assertTrue(childWin.canBeImeTarget()); imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */); @@ -365,8 +367,8 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); final ActivityRecord activity = createActivityRecord(mDisplayContent); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "startingWin"); + final WindowState startingWin = newWindowBuilder("startingWin", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); startingWin.setHasSurface(true); assertTrue(startingWin.canBeImeTarget()); final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class); @@ -385,10 +387,10 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeTargetReturnsNull_windowDidntRequestIme() { - final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, - new ActivityBuilder(mAtm).setCreateTask(true).build(), "app"); - final WindowState win2 = createWindow(null, TYPE_BASE_APPLICATION, - new ActivityBuilder(mAtm).setCreateTask(true).build(), "app2"); + final WindowState win1 = newWindowBuilder("app", TYPE_BASE_APPLICATION).setWindowToken( + new ActivityBuilder(mAtm).setCreateTask(true).build()).build(); + final WindowState win2 = newWindowBuilder("app2", TYPE_BASE_APPLICATION).setWindowToken( + new ActivityBuilder(mAtm).setCreateTask(true).build()).build(); mDisplayContent.setImeInputTarget(win1); mDisplayContent.setImeLayeringTarget(win2); @@ -404,8 +406,8 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); final ActivityRecord activity = createActivityRecord(mDisplayContent); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "startingWin"); + final WindowState startingWin = newWindowBuilder("startingWin", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); startingWin.setHasSurface(true); assertTrue(startingWin.canBeImeTarget()); final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class); @@ -433,8 +435,8 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); final ActivityRecord activity = createActivityRecord(mDisplayContent); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "startingWin"); + final WindowState startingWin = newWindowBuilder("startingWin", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); startingWin.setHasSurface(true); assertTrue(startingWin.canBeImeTarget()); @@ -532,8 +534,8 @@ public class DisplayContentTests extends WindowTestsBase { mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled; // Create a focusable window and check that focus is calculated correctly - final WindowState window1 = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1"); + final WindowState window1 = newWindowBuilder("window1", TYPE_BASE_APPLICATION).setDisplay( + mDisplayContent).build(); window1.mActivityRecord.mTargetSdk = targetSdk; updateFocusedWindow(); assertTrue(window1.isFocused()); @@ -549,7 +551,8 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord app2 = new ActivityBuilder(mAtm) .setTask(new TaskBuilder(mSupervisor).setDisplay(dc).build()) .setUseProcess(window1.getProcess()).setOnTop(true).build(); - final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, app2, "window2"); + final WindowState window2 = newWindowBuilder("window2", + TYPE_BASE_APPLICATION).setWindowToken(app2).build(); window2.mActivityRecord.mTargetSdk = targetSdk; updateFocusedWindow(); assertTrue(window2.isFocused()); @@ -616,7 +619,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testDisplayHasContent() { - final WindowState window = createWindow(null, TYPE_APPLICATION_OVERLAY, "window"); + final WindowState window = newWindowBuilder("window", TYPE_APPLICATION_OVERLAY).build(); setDrawnState(WindowStateAnimator.COMMIT_DRAW_PENDING, window); assertFalse(mDisplayContent.getLastHasContent()); // The pending draw state should be committed and the has-content state is also updated. @@ -632,7 +635,8 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testImeIsAttachedToDisplayForLetterboxedApp() { final DisplayContent dc = mDisplayContent; - final WindowState ws = createWindow(null, TYPE_APPLICATION, dc, "app window"); + final WindowState ws = newWindowBuilder("app window", TYPE_APPLICATION).setDisplay( + dc).build(); dc.setImeLayeringTarget(ws); dc.setImeInputTarget(ws); @@ -655,7 +659,8 @@ public class DisplayContentTests extends WindowTestsBase { final WindowState[] windows = new WindowState[types.length]; for (int i = 0; i < types.length; i++) { final int type = types[i]; - windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type); + windows[i] = newWindowBuilder("window-" + type, type).setDisplay( + displayContent).build(); windows[i].setHasSurface(true); windows[i].mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING; } @@ -887,7 +892,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testLayoutSeq_assignedDuringLayout() { final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w"); + final WindowState win = newWindowBuilder("w", TYPE_BASE_APPLICATION).setDisplay(dc).build(); performLayout(dc); @@ -902,10 +907,12 @@ public class DisplayContentTests extends WindowTestsBase { // Create a window that requests landscape orientation. It will define device orientation // by default. - final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w"); + final WindowState window = newWindowBuilder("w", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); window.mActivityRecord.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); - final WindowState keyguard = createWindow(null, TYPE_NOTIFICATION_SHADE , dc, "keyguard"); + final WindowState keyguard = newWindowBuilder("keyguard", + TYPE_NOTIFICATION_SHADE).setDisplay(dc).build(); keyguard.mHasSurface = true; keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; @@ -936,8 +943,8 @@ public class DisplayContentTests extends WindowTestsBase { // Create a window that requests a fixed orientation. It will define device orientation // by default. - final WindowState window = createWindow(null /* parent */, TYPE_APPLICATION_OVERLAY, dc, - "window"); + final WindowState window = newWindowBuilder("window", TYPE_APPLICATION_OVERLAY).setDisplay( + dc).build(); window.mHasSurface = true; window.mAttrs.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE; @@ -1003,12 +1010,14 @@ public class DisplayContentTests extends WindowTestsBase { public void testInputMethodTargetUpdateWhenSwitchingOnDisplays() { final DisplayContent newDisplay = createNewDisplay(); - final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); + final WindowState appWin = newWindowBuilder("appWin", TYPE_APPLICATION).setDisplay( + mDisplayContent).build(); final Task rootTask = mDisplayContent.getTopRootTask(); final ActivityRecord activity = rootTask.topRunningActivity(); doReturn(true).when(activity).shouldBeVisibleUnchecked(); - final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1"); + final WindowState appWin1 = newWindowBuilder("appWin1", TYPE_APPLICATION).setDisplay( + newDisplay).build(); final Task rootTask1 = newDisplay.getTopRootTask(); final ActivityRecord activity1 = rootTask1.topRunningActivity(); doReturn(true).when(activity1).shouldBeVisibleUnchecked(); @@ -1203,7 +1212,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_app() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.setImeLayeringTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); + dc.setImeLayeringTarget(newWindowBuilder("app", TYPE_BASE_APPLICATION).build()); dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()); assertEquals(dc.getImeTarget( IME_TARGET_LAYERING).getWindow().mActivityRecord.getSurfaceControl(), @@ -1213,7 +1222,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_app_notFullscreen() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "app")); + dc.setImeLayeringTarget(newWindowBuilder("app", TYPE_STATUS_BAR).build()); dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode( WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW); dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()); @@ -1235,7 +1244,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_noApp() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "statusBar")); + dc.setImeLayeringTarget(newWindowBuilder("statusBar", TYPE_STATUS_BAR).build()); dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()); assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent().getSurfaceControl()); @@ -1244,8 +1253,8 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testComputeImeParent_inputTargetNotUpdate() throws Exception { - WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1"); - WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2"); + WindowState app1 = newWindowBuilder("app1", TYPE_BASE_APPLICATION).build(); + WindowState app2 = newWindowBuilder("app2", TYPE_BASE_APPLICATION).build(); doReturn(true).when(mDisplayContent).shouldImeAttachedToApp(); mDisplayContent.setImeLayeringTarget(app1); mDisplayContent.setImeInputTarget(app1); @@ -1260,10 +1269,10 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testComputeImeParent_updateParentWhenTargetNotUseIme() throws Exception { - WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay"); + WindowState overlay = newWindowBuilder("overlay", TYPE_APPLICATION_OVERLAY).build(); overlay.setBounds(100, 100, 200, 200); overlay.mAttrs.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM; - WindowState app = createWindow(null, TYPE_BASE_APPLICATION, "app"); + WindowState app = newWindowBuilder("app", TYPE_BASE_APPLICATION).build(); mDisplayContent.setImeLayeringTarget(overlay); mDisplayContent.setImeInputTarget(app); assertFalse(mDisplayContent.shouldImeAttachedToApp()); @@ -1274,8 +1283,8 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeParent_remoteControlTarget() throws Exception { final DisplayContent dc = mDisplayContent; - WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1"); - WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2"); + WindowState app1 = newWindowBuilder("app1", TYPE_BASE_APPLICATION).build(); + WindowState app2 = newWindowBuilder("app2", TYPE_BASE_APPLICATION).build(); dc.setImeLayeringTarget(app1); dc.setImeInputTarget(app2); @@ -1301,7 +1310,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception { final DisplayContent dc = createNewDisplay(); - WindowState app = createWindow(null, TYPE_BASE_APPLICATION, dc, "app"); + WindowState app = newWindowBuilder("app", TYPE_BASE_APPLICATION).setDisplay(dc).build(); dc.setImeInputTarget(app); assertEquals(app, dc.computeImeControlTarget()); @@ -1316,7 +1325,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testComputeImeControlTarget() throws Exception { final DisplayContent dc = createNewDisplay(); dc.setRemoteInsetsController(createDisplayWindowInsetsController()); - dc.mCurrentFocus = createWindow(null, TYPE_BASE_APPLICATION, "app"); + dc.mCurrentFocus = newWindowBuilder("app", TYPE_BASE_APPLICATION).build(); // Expect returning null IME control target when the focus window has not yet been the // IME input target (e.g. IME is restarting) in fullscreen windowing mode. @@ -1332,7 +1341,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testComputeImeControlTarget_splitscreen() throws Exception { final DisplayContent dc = createNewDisplay(); - dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app")); + dc.setImeInputTarget(newWindowBuilder("app", TYPE_BASE_APPLICATION).build()); dc.getImeInputTarget().getWindowState().setWindowingMode( WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW); dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState()); @@ -1346,7 +1355,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testImeSecureFlagGetUpdatedAfterImeInputTarget() { // Verify IME window can get up-to-date secure flag update when the IME input target // set before setCanScreenshot called. - final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build(); SurfaceControl.Transaction t = mDisplayContent.mInputMethodWindow.getPendingTransaction(); spyOn(t); mDisplayContent.setImeInputTarget(app); @@ -1391,7 +1400,8 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testUpdateSystemGestureExclusion() throws Exception { final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); @@ -1423,11 +1433,12 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testCalculateSystemGestureExclusion() throws Exception { final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40))); - final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2"); + final WindowState win2 = newWindowBuilder("win2", TYPE_APPLICATION).setDisplay(dc).build(); win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50))); @@ -1451,11 +1462,12 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testCalculateSystemGestureExclusion_modal() throws Exception { final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "base"); + final WindowState win = newWindowBuilder("base", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win.setSystemGestureExclusion(Collections.singletonList(new Rect(0, 0, 1000, 1000))); - final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "modal"); + final WindowState win2 = newWindowBuilder("modal", TYPE_APPLICATION).setDisplay(dc).build(); win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win2.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION; win2.getAttrs().width = 10; @@ -1476,7 +1488,8 @@ public class DisplayContentTests extends WindowTestsBase { mWm.mConstants.mSystemGestureExcludedByPreQStickyImmersive = true; final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION; @@ -1500,7 +1513,8 @@ public class DisplayContentTests extends WindowTestsBase { mWm.mConstants.mSystemGestureExcludedByPreQStickyImmersive = true; final DisplayContent dc = createNewDisplay(); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setDisplay( + dc).build(); win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; win.getAttrs().privateFlags |= PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; @@ -1559,9 +1573,9 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testHybridRotationAnimation() { final DisplayContent displayContent = mDefaultDisplay; - final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar"); - final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar"); - final WindowState app = createWindow(null, TYPE_BASE_APPLICATION, "app"); + final WindowState statusBar = newWindowBuilder("statusBar", TYPE_STATUS_BAR).build(); + final WindowState navBar = newWindowBuilder("navBar", TYPE_NAVIGATION_BAR).build(); + final WindowState app = newWindowBuilder("app", TYPE_BASE_APPLICATION).build(); final WindowState[] windows = { statusBar, navBar, app }; makeWindowVisible(windows); final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); @@ -1863,6 +1877,11 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals("Display must be portrait after closing the translucent activity", Configuration.ORIENTATION_PORTRAIT, mDisplayContent.getConfiguration().orientation); + + mDisplayContent.setFixedRotationLaunchingAppUnchecked(nonTopVisible); + mDisplayContent.onTransitionFinished(); + assertFalse("Complete fixed rotation if not in a transition", + mDisplayContent.hasTopFixedRotationLaunchingApp()); } @Test @@ -2183,7 +2202,8 @@ public class DisplayContentTests extends WindowTestsBase { Task rootTask = createTask(display); Task task = createTaskInRootTask(rootTask, 0 /* userId */); WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window"); - WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot"); + WindowState behindWindow = newWindowBuilder("Screenshot", TYPE_SCREENSHOT).setDisplay( + display).build(); WindowState result = display.findScrollCaptureTargetWindow(behindWindow, ActivityTaskManager.INVALID_TASK_ID); @@ -2196,7 +2216,7 @@ public class DisplayContentTests extends WindowTestsBase { Task rootTask = createTask(display); Task task = createTaskInRootTask(rootTask, 0 /* userId */); WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window"); - WindowState invisible = createWindow(null, TYPE_APPLICATION, "invisible"); + WindowState invisible = newWindowBuilder("invisible", TYPE_APPLICATION).build(); invisible.mViewVisibility = View.INVISIBLE; // make canReceiveKeys return false WindowState result = display.findScrollCaptureTargetWindow(null, @@ -2209,7 +2229,7 @@ public class DisplayContentTests extends WindowTestsBase { DisplayContent display = createNewDisplay(); Task rootTask = createTask(display); Task task = createTaskInRootTask(rootTask, 0 /* userId */); - WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window"); + WindowState secureWindow = newWindowBuilder("Secure Window", TYPE_APPLICATION).build(); secureWindow.mAttrs.flags |= FLAG_SECURE; WindowState result = display.findScrollCaptureTargetWindow(null, @@ -2222,7 +2242,7 @@ public class DisplayContentTests extends WindowTestsBase { DisplayContent display = createNewDisplay(); Task rootTask = createTask(display); Task task = createTaskInRootTask(rootTask, 0 /* userId */); - WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window"); + WindowState secureWindow = newWindowBuilder("Secure window", TYPE_APPLICATION).build(); secureWindow.mAttrs.flags |= FLAG_SECURE; WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId); @@ -2235,7 +2255,8 @@ public class DisplayContentTests extends WindowTestsBase { Task rootTask = createTask(display); Task task = createTaskInRootTask(rootTask, 0 /* userId */); WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window"); - WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot"); + WindowState behindWindow = newWindowBuilder("Screenshot", TYPE_SCREENSHOT).setDisplay( + display).build(); WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId); assertEquals(window, result); @@ -2248,7 +2269,8 @@ public class DisplayContentTests extends WindowTestsBase { Task task = createTaskInRootTask(rootTask, 0 /* userId */); WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window"); window.mViewVisibility = View.INVISIBLE; // make canReceiveKeys return false - WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot"); + WindowState behindWindow = newWindowBuilder("Screenshot", TYPE_SCREENSHOT).setDisplay( + display).build(); WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId); assertEquals(window, result); @@ -2317,9 +2339,10 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD }) @Test public void testComputeImeTarget_shouldNotCheckOutdatedImeTargetLayerWhenRemoved() { - final WindowState child1 = createWindow(mAppWindow, FIRST_SUB_WINDOW, "child1"); - final WindowState nextImeTargetApp = createWindow(null /* parent */, - TYPE_BASE_APPLICATION, "nextImeTargetApp"); + final WindowState child1 = newWindowBuilder("child1", FIRST_SUB_WINDOW).setParent( + mAppWindow).build(); + final WindowState nextImeTargetApp = newWindowBuilder("nextImeTargetApp", + TYPE_BASE_APPLICATION).build(); spyOn(child1); doReturn(false).when(mDisplayContent).shouldImeAttachedToApp(); mDisplayContent.setImeLayeringTarget(child1); @@ -2353,7 +2376,8 @@ public class DisplayContentTests extends WindowTestsBase { // Preparation: Simulate snapshot Task. ActivityRecord act1 = createActivityRecord(mDisplayContent); - final WindowState appWin1 = createWindow(null, TYPE_BASE_APPLICATION, act1, "appWin1"); + final WindowState appWin1 = newWindowBuilder("appWin1", + TYPE_BASE_APPLICATION).setWindowToken(act1).build(); spyOn(appWin1); spyOn(appWin1.mWinAnimator); appWin1.setHasSurface(true); @@ -2372,7 +2396,8 @@ public class DisplayContentTests extends WindowTestsBase { // Test step 2: Simulate launching appWin2 and appWin1 is in app transition. ActivityRecord act2 = createActivityRecord(mDisplayContent); - final WindowState appWin2 = createWindow(null, TYPE_BASE_APPLICATION, act2, "appWin2"); + final WindowState appWin2 = newWindowBuilder("appWin2", + TYPE_BASE_APPLICATION).setWindowToken(act2).build(); appWin2.setHasSurface(true); assertTrue(appWin2.canBeImeTarget()); doReturn(true).when(appWin1).inTransitionSelfOrParent(); @@ -2394,7 +2419,8 @@ public class DisplayContentTests extends WindowTestsBase { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( + activity).build(); task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); doReturn(true).when(task).okToAnimate(); ArrayList<WindowContainer> sources = new ArrayList<>(); @@ -2420,7 +2446,8 @@ public class DisplayContentTests extends WindowTestsBase { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( + activity).build(); mDisplayContent.setImeLayeringTarget(win); mDisplayContent.setImeInputTarget(win); @@ -2446,7 +2473,8 @@ public class DisplayContentTests extends WindowTestsBase { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( + activity).build(); win.onSurfaceShownChanged(true); makeWindowVisible(win, mDisplayContent.mInputMethodWindow); task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); @@ -2471,7 +2499,8 @@ public class DisplayContentTests extends WindowTestsBase { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); + final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( + activity).build(); makeWindowVisible(mDisplayContent.mInputMethodWindow); mDisplayContent.setImeLayeringTarget(win); @@ -2687,7 +2716,8 @@ public class DisplayContentTests extends WindowTestsBase { public void testKeyguardGoingAwayWhileAodShown() { mDisplayContent.getDisplayPolicy().setAwake(true); - final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); + final WindowState appWin = newWindowBuilder("appWin", TYPE_APPLICATION).setDisplay( + mDisplayContent).build(); final ActivityRecord activity = appWin.mActivityRecord; mAtm.mKeyguardController.setKeyguardShown(appWin.getDisplayId(), true /* keyguardShowing */, @@ -2713,15 +2743,15 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = W_INPUT_METHOD) @Test public void testImeChildWindowFocusWhenImeLayeringTargetChanges() { - final WindowState imeChildWindow = - createWindow(mImeWindow, TYPE_APPLICATION_ATTACHED_DIALOG, "imeChildWindow"); + final WindowState imeChildWindow = newWindowBuilder("imeChildWindow", + TYPE_APPLICATION_ATTACHED_DIALOG).setParent(mImeWindow).build(); makeWindowVisibleAndDrawn(imeChildWindow, mImeWindow); assertTrue(imeChildWindow.canReceiveKeys()); mDisplayContent.setInputMethodWindowLocked(mImeWindow); // Verify imeChildWindow can be focused window if the next IME target requests IME visible. - final WindowState imeAppTarget = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); + final WindowState imeAppTarget = newWindowBuilder("imeAppTarget", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); mDisplayContent.setImeLayeringTarget(imeAppTarget); spyOn(imeAppTarget); doReturn(true).when(imeAppTarget).isRequestedVisible(ime()); @@ -2729,8 +2759,8 @@ public class DisplayContentTests extends WindowTestsBase { // Verify imeChildWindow doesn't be focused window if the next IME target does not // request IME visible. - final WindowState nextImeAppTarget = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget"); + final WindowState nextImeAppTarget = newWindowBuilder("nextImeAppTarget", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); mDisplayContent.setImeLayeringTarget(nextImeAppTarget); assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow()); } @@ -2738,22 +2768,22 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = W_INPUT_METHOD) @Test public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() { - final WindowState imeMenuDialog = - createWindow(null, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog"); + final WindowState imeMenuDialog = newWindowBuilder("imeMenuDialog", + TYPE_INPUT_METHOD_DIALOG).build(); makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow); assertTrue(imeMenuDialog.canReceiveKeys()); mDisplayContent.setInputMethodWindowLocked(mImeWindow); // Verify imeMenuDialog can be focused window if the next IME target requests IME visible. - final WindowState imeAppTarget = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); + final WindowState imeAppTarget = newWindowBuilder("imeAppTarget", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); mDisplayContent.setImeLayeringTarget(imeAppTarget); imeAppTarget.setRequestedVisibleTypes(ime()); assertEquals(imeMenuDialog, mDisplayContent.findFocusedWindow()); // Verify imeMenuDialog doesn't be focused window if the next IME target is closing. - final WindowState nextImeAppTarget = - createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget"); + final WindowState nextImeAppTarget = newWindowBuilder("nextImeAppTarget", + TYPE_BASE_APPLICATION).setDisplay(mDisplayContent).build(); makeWindowVisibleAndDrawn(nextImeAppTarget); // Even if the app still requests IME, the ime dialog should not gain focus if the target // app is invisible. @@ -2765,10 +2795,12 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testKeepClearAreasMultipleWindows() { - final WindowState w1 = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent, "w1"); + final WindowState w1 = newWindowBuilder("w1", TYPE_NAVIGATION_BAR).setDisplay( + mDisplayContent).build(); final Rect rect1 = new Rect(0, 0, 10, 10); w1.setKeepClearAreas(Arrays.asList(rect1), Collections.emptyList()); - final WindowState w2 = createWindow(null, TYPE_NOTIFICATION_SHADE, mDisplayContent, "w2"); + final WindowState w2 = newWindowBuilder("w2", TYPE_NOTIFICATION_SHADE).setDisplay( + mDisplayContent).build(); final Rect rect2 = new Rect(10, 10, 20, 20); w2.setKeepClearAreas(Arrays.asList(rect2), Collections.emptyList()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 1015651438c3..ceb06497adbc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -76,7 +76,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { @Before public void setUp() throws Exception { - mWindow = spy(createWindow(null, TYPE_APPLICATION, "window")); + mWindow = spy(newWindowBuilder("window", TYPE_APPLICATION).build()); spyOn(mStatusBarWindow); spyOn(mNavBarWindow); @@ -147,7 +147,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { public void addingWindow_withInsetsTypes() { mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one. - final WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "statusBar"); + final WindowState win = newWindowBuilder("statusBar", TYPE_STATUS_BAR_SUB_PANEL).build(); final Binder owner = new Binder(); win.mAttrs.providedInsets = new InsetsFrameProvider[] { new InsetsFrameProvider(owner, 0, WindowInsets.Type.statusBars()), diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index 27d46fc4e39e..ea925c019b77 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -76,7 +76,7 @@ import org.junit.runner.RunWith; public class DisplayPolicyTests extends WindowTestsBase { private WindowState createOpaqueFullscreen(boolean hasLightNavBar) { - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "opaqueFullscreen"); + final WindowState win = newWindowBuilder("opaqueFullscreen", TYPE_BASE_APPLICATION).build(); final WindowManager.LayoutParams attrs = win.mAttrs; attrs.width = MATCH_PARENT; attrs.height = MATCH_PARENT; @@ -99,7 +99,7 @@ public class DisplayPolicyTests extends WindowTestsBase { } private WindowState createDimmingDialogWindow(boolean canBeImTarget) { - final WindowState win = spy(createWindow(null, TYPE_APPLICATION, "dimmingDialog")); + final WindowState win = spy(newWindowBuilder("dimmingDialog", TYPE_APPLICATION).build()); final WindowManager.LayoutParams attrs = win.mAttrs; attrs.width = WRAP_CONTENT; attrs.height = WRAP_CONTENT; @@ -111,7 +111,7 @@ public class DisplayPolicyTests extends WindowTestsBase { private WindowState createInputMethodWindow(boolean visible, boolean drawNavBar, boolean hasLightNavBar) { - final WindowState win = createWindow(null, TYPE_INPUT_METHOD, "inputMethod"); + final WindowState win = newWindowBuilder("inputMethod", TYPE_INPUT_METHOD).build(); final WindowManager.LayoutParams attrs = win.mAttrs; attrs.width = MATCH_PARENT; attrs.height = MATCH_PARENT; @@ -301,7 +301,7 @@ public class DisplayPolicyTests extends WindowTestsBase { } private WindowState createApplicationWindow() { - final WindowState win = createWindow(null, TYPE_APPLICATION, "Application"); + final WindowState win = newWindowBuilder("Application", TYPE_APPLICATION).build(); final WindowManager.LayoutParams attrs = win.mAttrs; attrs.width = MATCH_PARENT; attrs.height = MATCH_PARENT; @@ -312,7 +312,7 @@ public class DisplayPolicyTests extends WindowTestsBase { } private WindowState createBaseApplicationWindow() { - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "Application"); + final WindowState win = newWindowBuilder("Application", TYPE_BASE_APPLICATION).build(); final WindowManager.LayoutParams attrs = win.mAttrs; attrs.width = MATCH_PARENT; attrs.height = MATCH_PARENT; @@ -450,7 +450,7 @@ public class DisplayPolicyTests extends WindowTestsBase { displayPolicy.getDecorInsetsInfo(Surface.ROTATION_90, di.logicalHeight, di.logicalWidth); // Add a window that provides the same insets in current rotation. But it specifies // different insets in other rotations. - final WindowState bar2 = createWindow(null, navbar.mAttrs.type, "bar2"); + final WindowState bar2 = newWindowBuilder("bar2", navbar.mAttrs.type).build(); bar2.mAttrs.providedInsets = new InsetsFrameProvider[] { new InsetsFrameProvider(bar2, 0, WindowInsets.Type.navigationBars()) .setInsetsSize(Insets.of(0, 0, 0, NAV_BAR_HEIGHT)) diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 429a396ad997..de4b6fac7abf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -150,8 +150,8 @@ public class DragDropControllerTests extends WindowTestsBase { mProcess).build(); // Use a new TestIWindow so we don't collect events for other windows - final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, activity, name, - ownerId, false, new TestIWindow()); + final WindowState window = newWindowBuilder(name, TYPE_BASE_APPLICATION).setWindowToken( + activity).setOwnerId(ownerId).setClientWindow(new TestIWindow()).build(); InputChannel channel = new InputChannel(); window.openInputChannel(channel); window.mHasSurface = true; @@ -249,7 +249,7 @@ public class DragDropControllerTests extends WindowTestsBase { mTarget.mDeferDragStateClosed = true; mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0); // Verify the drop event includes the drag surface - mTarget.handleMotionEvent(false, 0, 0); + mTarget.handleMotionEvent(false, mWindow.getDisplayId(), 0, 0); final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); assertTrue(dropEvent.getDragSurface() != null); @@ -296,7 +296,7 @@ public class DragDropControllerTests extends WindowTestsBase { 0).getClipData().willParcelWithActivityInfo()); mTarget.reportDropWindow(globalInterceptWindow.mInputChannelToken, 0, 0); - mTarget.handleMotionEvent(false, 0, 0); + mTarget.handleMotionEvent(false, globalInterceptWindow.getDisplayId(), 0, 0); mToken = globalInterceptWindow.mClient.asBinder(); // Verify the drop event is only sent for the global intercept window @@ -334,8 +334,8 @@ public class DragDropControllerTests extends WindowTestsBase { try { mTarget.mDeferDragStateClosed = true; mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0); - // // Verify the drop event does not have the drag flags - mTarget.handleMotionEvent(false, 0, 0); + // Verify the drop event does not have the drag flags + mTarget.handleMotionEvent(false, mWindow.getDisplayId(), 0, 0); final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); assertTrue(dropEvent.getDragFlags() == (View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG)); @@ -520,7 +520,7 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify after consuming that the drag surface is relinquished mTarget.reportDropWindow(otherWindow.mInputChannelToken, 0, 0); - mTarget.handleMotionEvent(false, 0, 0); + mTarget.handleMotionEvent(false, otherWindow.getDisplayId(), 0, 0); mToken = otherWindow.mClient.asBinder(); mTarget.reportDropResult(otherIWindow, true); @@ -551,7 +551,7 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify after consuming that the drag surface is relinquished mTarget.reportDropWindow(otherWindow.mInputChannelToken, 0, 0); - mTarget.handleMotionEvent(false, 0, 0); + mTarget.handleMotionEvent(false, otherWindow.getDisplayId(), 0, 0); mToken = otherWindow.mClient.asBinder(); mTarget.reportDropResult(otherIWindow, false); @@ -586,7 +586,8 @@ public class DragDropControllerTests extends WindowTestsBase { ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, mWindow.getDisplayId(), + invalidXY, invalidXY); mTarget.reportDropResult(mWindow.mClient, false); mTarget.onUnhandledDropCallback(true); mToken = null; @@ -610,7 +611,8 @@ public class DragDropControllerTests extends WindowTestsBase { ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, mWindow.getDisplayId(), + invalidXY, invalidXY); mTarget.onUnhandledDropCallback(true); mToken = null; try { @@ -632,7 +634,8 @@ public class DragDropControllerTests extends WindowTestsBase { startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was not called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, mDisplayContent.getDisplayId(), + invalidXY, invalidXY); mToken = null; try { verify(listener, never()).onUnhandledDrop(any(), any()); @@ -654,7 +657,8 @@ public class DragDropControllerTests extends WindowTestsBase { ClipData.newPlainText("label", "Test"), () -> { // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, + mDisplayContent.getDisplayId(), invalidXY, invalidXY); // Verify that the unhandled drop listener callback timeout has been scheduled final Handler handler = mTarget.getHandler(); @@ -673,7 +677,8 @@ public class DragDropControllerTests extends WindowTestsBase { private void doDragAndDrop(int flags, ClipData data, float dropX, float dropY) { startDrag(flags, data, () -> { mTarget.reportDropWindow(mWindow.mInputChannelToken, dropX, dropY); - mTarget.handleMotionEvent(false /* keepHandling */, dropX, dropY); + mTarget.handleMotionEvent(false /* keepHandling */, mWindow.getDisplayId(), dropX, + dropY); mToken = mWindow.mClient.asBinder(); }); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java index 7e1de4762681..51e02405e489 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java @@ -62,6 +62,8 @@ public class LetterboxAttachInputTest extends WindowTestsBase { private Letterbox mLetterbox; private LetterboxTest.SurfaceControlMocker mSurfaces; + private WindowState mWindowState; + @Before public void setUp() throws Exception { mSurfaces = new LetterboxTest.SurfaceControlMocker(); @@ -72,6 +74,7 @@ public class LetterboxAttachInputTest extends WindowTestsBase { doReturn(false).when(letterboxOverrides).hasWallpaperBackgroundForLetterbox(); doReturn(0).when(letterboxOverrides).getLetterboxWallpaperBlurRadiusPx(); doReturn(0.5f).when(letterboxOverrides).getLetterboxWallpaperDarkScrimAlpha(); + mWindowState = createWindowState(); mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, mock(AppCompatReachabilityPolicy.class), letterboxOverrides, () -> mock(SurfaceControl.class)); @@ -83,7 +86,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testSurface_createdHasSlipperyInput_scrollingFromLetterboxDisabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); assertNotNull(mSurfaces.top); @@ -100,7 +102,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testInputSurface_notCreated_scrollingFromLetterboxDisabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); assertNull(mSurfaces.topInput); @@ -111,7 +112,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testSurface_createdHasNoInput_scrollingFromLetterboxEnabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); assertNotNull(mSurfaces.top); @@ -124,7 +124,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testInputSurface_createdHasSpyInput_scrollingFromLetterboxEnabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); assertNotNull(mSurfaces.topInput); @@ -141,7 +140,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testInputSurfaceOrigin_applied_scrollingFromLetterboxEnabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); verify(mTransaction).setPosition(mSurfaces.topInput, -1000, -2000); @@ -152,7 +150,6 @@ public class LetterboxAttachInputTest extends WindowTestsBase { public void testInputSurfaceOrigin_changeCausesReapply_scrollingFromLetterboxEnabled() { mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); - attachInput(); applySurfaceChanges(); clearInvocations(mTransaction); mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0)); @@ -166,13 +163,12 @@ public class LetterboxAttachInputTest extends WindowTestsBase { private void applySurfaceChanges() { mLetterbox.applySurfaceChanges(/* syncTransaction */ mTransaction, - /* pendingTransaction */ mTransaction); + /* pendingTransaction */ mTransaction, mWindowState); } - private void attachInput() { + private WindowState createWindowState() { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); final WindowToken windowToken = createTestWindowToken(0, mDisplayContent); - WindowState windowState = createWindowState(attrs, windowToken); - mLetterbox.attachInput(windowState); + return createWindowState(attrs, windowToken); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index 0baa5171a541..a51a44f6167b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -70,6 +70,7 @@ public class LetterboxTest { private SurfaceControl mParentSurface = mock(SurfaceControl.class); private AppCompatLetterboxOverrides mLetterboxOverrides; + private WindowState mWindowState; @Before public void setUp() throws Exception { @@ -81,6 +82,7 @@ public class LetterboxTest { doReturn(false).when(mLetterboxOverrides).hasWallpaperBackgroundForLetterbox(); doReturn(0).when(mLetterboxOverrides).getLetterboxWallpaperBlurRadiusPx(); doReturn(0.5f).when(mLetterboxOverrides).getLetterboxWallpaperDarkScrimAlpha(); + mWindowState = mock(WindowState.class); mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, mock(AppCompatReachabilityPolicy.class), mLetterboxOverrides, () -> mParentSurface); mTransaction = spy(StubTransaction.class); @@ -320,7 +322,7 @@ public class LetterboxTest { private void applySurfaceChanges() { mLetterbox.applySurfaceChanges(/* syncTransaction */ mTransaction, - /* pendingTransaction */ mTransaction); + /* pendingTransaction */ mTransaction, mWindowState); } static class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> { diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 699ed0263756..7e62b89d35bb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -1348,13 +1348,19 @@ public class RootWindowContainerTests extends WindowTestsBase { WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); doReturn(rootTask3).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); - // Set up user ids and visibility + // Set up child tasks inside root tasks and set some of them visible + final Task task1 = new TaskBuilder(mSupervisor).setOnTop(true).setParentTask( + rootTask1).build(); + final Task task2 = new TaskBuilder(mSupervisor).setOnTop(true).setParentTask( + rootTask2).build(); + final Task task3 = new TaskBuilder(mSupervisor).setOnTop(true).setParentTask( + rootTask3).build(); rootTask1.mUserId = mRootWindowContainer.mCurrentUser; rootTask2.mUserId = mRootWindowContainer.mCurrentUser; rootTask3.mUserId = mRootWindowContainer.mCurrentUser; - rootTask1.mVisibleRequested = false; - rootTask2.mVisibleRequested = true; - rootTask3.mVisibleRequested = true; + doReturn(false).when(task1).isVisible(); + doReturn(true).when(task2).isVisible(); + doReturn(true).when(task3).isVisible(); // Switch to a different user int currentUser = mRootWindowContainer.mCurrentUser; 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 201ff51f1495..6a738ae54dcd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -391,7 +391,6 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_IMMERSIVE_APP_REPOSITIONING) @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED}) public void testRepositionLandscapeImmersiveAppWithDisplayCutout() { final int dw = 2100; @@ -3783,7 +3782,6 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_IMMERSIVE_APP_REPOSITIONING) public void testImmersiveLetterboxAlignedToBottom_OverlappingNavbar() { assertLandscapeActivityAlignedToBottomWithNavbar(true /* immersive */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 0cd036f0c61c..19c1ce2616af 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -741,16 +741,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Not allowed because TaskFragments are not organized by the caller organizer. assertApplyTransactionDisallowed(mTransaction); - assertNull(mTaskFragment.getAdjacentTaskFragment()); - assertNull(taskFragment2.getAdjacentTaskFragment()); + assertFalse(mTaskFragment.hasAdjacentTaskFragment()); + assertFalse(taskFragment2.hasAdjacentTaskFragment()); mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, "Test:TaskFragmentOrganizer" /* processName */); // Not allowed because TaskFragment2 is not organized by the caller organizer. assertApplyTransactionDisallowed(mTransaction); - assertNull(mTaskFragment.getAdjacentTaskFragment()); - assertNull(taskFragment2.getAdjacentTaskFragment()); + assertFalse(mTaskFragment.hasAdjacentTaskFragment()); + assertFalse(taskFragment2.hasAdjacentTaskFragment()); mTaskFragment.onTaskFragmentOrganizerRemoved(); taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, @@ -758,14 +758,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Not allowed because mTaskFragment is not organized by the caller organizer. assertApplyTransactionDisallowed(mTransaction); - assertNull(mTaskFragment.getAdjacentTaskFragment()); - assertNull(taskFragment2.getAdjacentTaskFragment()); + assertFalse(mTaskFragment.hasAdjacentTaskFragment()); + assertFalse(taskFragment2.hasAdjacentTaskFragment()); mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, "Test:TaskFragmentOrganizer" /* processName */); assertApplyTransactionAllowed(mTransaction); - assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment()); + assertTrue(mTaskFragment.isAdjacentTo(taskFragment2)); } @Test @@ -790,14 +790,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Not allowed because TaskFragment is not organized by the caller organizer. assertApplyTransactionDisallowed(mTransaction); - assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment()); + assertTrue(mTaskFragment.isAdjacentTo(taskFragment2)); mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */, "Test:TaskFragmentOrganizer" /* processName */); assertApplyTransactionAllowed(mTransaction); - assertNull(mTaskFragment.getAdjacentTaskFragment()); - assertNull(taskFragment2.getAdjacentTaskFragment()); + assertFalse(mTaskFragment.hasAdjacentTaskFragment()); + assertFalse(taskFragment2.hasAdjacentTaskFragment()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index dafa96f91812..35a2546fca1a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -365,7 +365,7 @@ public class TaskFragmentTest extends WindowTestsBase { assertEquals(taskFragmentBounds, activity.getBounds()); assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode()); - assertEquals(taskFragment1, taskFragment0.getAdjacentTaskFragment()); + assertTrue(taskFragment0.isAdjacentTo(taskFragment1)); assertEquals(taskFragment1, taskFragment0.getCompanionTaskFragment()); assertNotEquals(TaskFragmentAnimationParams.DEFAULT, taskFragment0.getAnimationParams()); @@ -381,7 +381,7 @@ public class TaskFragmentTest extends WindowTestsBase { assertEquals(taskBounds, taskFragment0.getBounds()); assertEquals(taskBounds, activity.getBounds()); assertEquals(Configuration.EMPTY, taskFragment0.getRequestedOverrideConfiguration()); - assertNull(taskFragment0.getAdjacentTaskFragment()); + assertFalse(taskFragment0.hasAdjacentTaskFragment()); assertNull(taskFragment0.getCompanionTaskFragment()); assertEquals(TaskFragmentAnimationParams.DEFAULT, taskFragment0.getAnimationParams()); // Because the whole Task is entering PiP, no need to record for future reparent. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java index 6655932b060b..c6b2a6b8d42f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -45,12 +46,15 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import android.window.TaskSnapshot; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + import com.google.android.collect.Sets; import org.junit.Test; @@ -285,4 +289,27 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { assertFalse(success); } + + @Test + @EnableFlags(Flags.FLAG_EXCLUDE_DRAWING_APP_THEME_SNAPSHOT_FROM_LOCK) + public void testRecordTaskSnapshot() { + spyOn(mWm.mTaskSnapshotController.mCache); + spyOn(mWm.mTaskSnapshotController); + doReturn(false).when(mWm.mTaskSnapshotController).shouldDisableSnapshots(); + + final WindowState normalWindow = createWindow(null, + FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow"); + final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() + .setTopActivityComponent(normalWindow.mActivityRecord.mActivityComponent).build(); + doReturn(snapshot).when(mWm.mTaskSnapshotController).snapshot(any()); + final Task task = normalWindow.mActivityRecord.getTask(); + mWm.mTaskSnapshotController.recordSnapshot(task); + verify(mWm.mTaskSnapshotController.mCache).putSnapshot(eq(task), any()); + clearInvocations(mWm.mTaskSnapshotController.mCache); + + normalWindow.mAttrs.flags |= FLAG_SECURE; + mWm.mTaskSnapshotController.recordSnapshot(task); + waitHandlerIdle(mWm.mH); + verify(mWm.mTaskSnapshotController.mCache).putSnapshot(eq(task), any()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index da4c522834a6..1281be5132d3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -909,8 +909,8 @@ public class WindowOrganizerTests extends WindowTestsBase { WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setAdjacentRoots(info1.token, info2.token); mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); - assertEquals(task1.getAdjacentTaskFragment(), task2); - assertEquals(task2.getAdjacentTaskFragment(), task1); + assertTrue(task1.isAdjacentTo(task2)); + assertTrue(task2.isAdjacentTo(task1)); wct = new WindowContainerTransaction(); wct.setLaunchAdjacentFlagRoot(info1.token); @@ -921,8 +921,8 @@ public class WindowOrganizerTests extends WindowTestsBase { wct.clearAdjacentRoots(info1.token); wct.clearLaunchAdjacentFlagRoot(info1.token); mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); - assertEquals(task1.getAdjacentTaskFragment(), null); - assertEquals(task2.getAdjacentTaskFragment(), null); + assertFalse(task1.hasAdjacentTaskFragment()); + assertFalse(task2.hasAdjacentTaskFragment()); assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null); } diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java index 34f0c191ecf5..fe9f63615757 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java +++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java @@ -76,6 +76,7 @@ public class IntegrationTests { private ActivityTestRule<EmptyActivity> mEmptyActivityRule = new ActivityTestRule<>(EmptyActivity.class, false , true); + @Before public void setUp() { mInstrumentation = InstrumentationRegistry.getInstrumentation(); @@ -163,7 +164,7 @@ public class IntegrationTests { // of that state. for (int i = 0; i < uiStates.size(); i++) { StateTracker.StateData stateData = uiStates.get(i); - if (stateData.mWidgetCategory.equals(AppJankStats.ANIMATION)) { + if (stateData.mWidgetCategory.equals(AppJankStats.WIDGET_CATEGORY_ANIMATION)) { assertNotEquals(Long.MAX_VALUE, stateData.mVsyncIdEnd); } } diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java index 30c568be7716..c90595782cd1 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java @@ -215,7 +215,8 @@ public class JankDataProcessorTest { assertEquals(jankStats.getJankyFrameCount() * 2, pendingStat.getJankyFrames()); assertEquals(jankStats.getTotalFrameCount() * 2, pendingStat.getTotalFrames()); - int[] originalHistogramBuckets = jankStats.getFrameOverrunHistogram().getBucketCounters(); + int[] originalHistogramBuckets = + jankStats.getRelativeFrameTimeHistogram().getBucketCounters(); int[] frameOverrunBuckets = pendingStat.getFrameOverrunBuckets(); for (int i = 0; i < frameOverrunBuckets.length; i++) { diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java index 0b4d97ed20d6..df92898d76b1 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java @@ -17,7 +17,7 @@ package android.app.jank.tests; import android.app.jank.AppJankStats; -import android.app.jank.FrameOverrunHistogram; +import android.app.jank.RelativeFrameTimeHistogram; public class JankUtils { private static final int APP_ID = 25; @@ -29,8 +29,8 @@ public class JankUtils { AppJankStats jankStats = new AppJankStats( /*App Uid*/APP_ID, /*Widget Id*/"test widget id", - /*Widget Category*/AppJankStats.SCROLL, - /*Widget State*/AppJankStats.SCROLLING, + /*Widget Category*/AppJankStats.WIDGET_CATEGORY_SCROLL, + /*Widget State*/AppJankStats.WIDGET_STATE_SCROLLING, /*Total Frames*/100, /*Janky Frames*/25, getOverrunHistogram() @@ -41,12 +41,12 @@ public class JankUtils { /** * Returns a mock histogram to be used with an AppJankStats object. */ - public static FrameOverrunHistogram getOverrunHistogram() { - FrameOverrunHistogram overrunHistogram = new FrameOverrunHistogram(); - overrunHistogram.addFrameOverrunMillis(-2); - overrunHistogram.addFrameOverrunMillis(1); - overrunHistogram.addFrameOverrunMillis(5); - overrunHistogram.addFrameOverrunMillis(25); + public static RelativeFrameTimeHistogram getOverrunHistogram() { + RelativeFrameTimeHistogram overrunHistogram = new RelativeFrameTimeHistogram(); + overrunHistogram.addRelativeFrameTimeMillis(-2); + overrunHistogram.addRelativeFrameTimeMillis(1); + overrunHistogram.addRelativeFrameTimeMillis(5); + overrunHistogram.addRelativeFrameTimeMillis(25); return overrunHistogram; } } diff --git a/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java index 5fff46038ead..71796d64ddee 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java +++ b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java @@ -45,8 +45,8 @@ public class TestWidget extends View { */ public void simulateAnimationStarting() { if (jankTrackerCreated()) { - mJankTracker.addUiState(AppJankStats.ANIMATION, - Integer.toString(this.getId()), AppJankStats.ANIMATING); + mJankTracker.addUiState(AppJankStats.WIDGET_CATEGORY_ANIMATION, + Integer.toString(this.getId()), AppJankStats.WIDGET_STATE_ANIMATING); } } @@ -55,8 +55,8 @@ public class TestWidget extends View { */ public void simulateAnimationEnding() { if (jankTrackerCreated()) { - mJankTracker.removeUiState(AppJankStats.ANIMATION, - Integer.toString(this.getId()), AppJankStats.ANIMATING); + mJankTracker.removeUiState(AppJankStats.WIDGET_CATEGORY_ANIMATION, + Integer.toString(this.getId()), AppJankStats.WIDGET_STATE_ANIMATING); } } diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java index 700856c50bae..14c8de8db5fc 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java @@ -819,7 +819,7 @@ public class GraphicsActivity extends Activity { private List<Float> getExpectedFrameRateForCompatibility(int compatibility) { assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED for compatibility " + compatibility, - compatibility == Surface.FRAME_RATE_COMPATIBILITY_GTE); + compatibility == Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST); Display display = getDisplay(); List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display) diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java index 4d4827676c74..f1d4dc6b8faf 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java @@ -85,7 +85,8 @@ public class SurfaceControlTest { @Test public void testSurfaceControlFrameRateCompatibilityGte() throws InterruptedException { GraphicsActivity activity = mActivityRule.getActivity(); - activity.testSurfaceControlFrameRateCompatibility(Surface.FRAME_RATE_COMPATIBILITY_GTE); + activity.testSurfaceControlFrameRateCompatibility( + Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST); } @Test diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt index 2e7b20763b9e..2db8b1e18ec8 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt @@ -29,6 +29,7 @@ import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.parsers.WindowManagerStateHelper import android.tools.traces.wm.WindowingMode import android.view.KeyEvent.KEYCODE_LEFT_BRACKET +import android.view.KeyEvent.KEYCODE_MINUS import android.view.KeyEvent.KEYCODE_RIGHT_BRACKET import android.view.KeyEvent.META_META_ON import android.view.WindowInsets @@ -160,10 +161,21 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : ?: error("Unable to find resource $MINIMIZE_BUTTON_VIEW\n") } - fun minimizeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice, isPip: Boolean = false) { - val caption = getCaptionForTheApp(wmHelper, device) - val minimizeButton = getMinimizeButtonForTheApp(caption) - minimizeButton.click() + fun minimizeDesktopApp( + wmHelper: WindowManagerStateHelper, + device: UiDevice, + isPip: Boolean = false, + usingKeyboard: Boolean = false, + ) { + if (usingKeyboard) { + val keyEventHelper = KeyEventHelper(getInstrumentation()) + keyEventHelper.press(KEYCODE_MINUS, META_META_ON) + } else { + val caption = getCaptionForTheApp(wmHelper, device) + val minimizeButton = getMinimizeButtonForTheApp(caption) + minimizeButton.click() + } + wmHelper .StateSyncBuilder() .withAppTransitionIdle() @@ -226,8 +238,7 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : toLeft: Boolean, ) { val bracketKey = if (toLeft) KEYCODE_LEFT_BRACKET else KEYCODE_RIGHT_BRACKET - keyEventHelper.actionDown(bracketKey, META_META_ON) - keyEventHelper.actionUp(bracketKey, META_META_ON) + keyEventHelper.press(bracketKey, META_META_ON) waitAndVerifySnapResize(wmHelper, context, toLeft) } diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/KeyEventHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/KeyEventHelper.kt index ebd8cc3ce1b4..55ed09154aee 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/KeyEventHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/KeyEventHelper.kt @@ -29,6 +29,10 @@ import android.view.KeyEvent class KeyEventHelper( private val instr: Instrumentation, ) { + fun press(keyCode: Int, metaState: Int = 0) { + actionDown(keyCode, metaState) + actionUp(keyCode, metaState) + } fun actionDown(keyCode: Int, metaState: Int = 0, time: Long = SystemClock.uptimeMillis()) { injectKeyEvent(ACTION_DOWN, keyCode, metaState, downTime = time, eventTime = time) diff --git a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt index 281837920548..860d9f680c4c 100644 --- a/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt +++ b/tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt @@ -16,10 +16,17 @@ package com.android.test.input +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule + import android.view.KeyCharacterMap import android.view.KeyEvent +import com.android.hardware.input.Flags + import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Rule import org.junit.Test /** @@ -30,26 +37,38 @@ import org.junit.Test * */ class KeyCharacterMapTest { + @get:Rule + val setFlagsRule = SetFlagsRule() + @Test + @EnableFlags(Flags.FLAG_REMOVE_FALLBACK_MODIFIERS) fun testGetFallback() { // Based off of VIRTUAL kcm fallbacks. val keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD) // One modifier fallback. - assertEquals( - keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE, - KeyEvent.META_CTRL_ON).keyCode, - KeyEvent.KEYCODE_LANGUAGE_SWITCH) + val oneModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE, + KeyEvent.META_CTRL_ON) + assertEquals(KeyEvent.KEYCODE_LANGUAGE_SWITCH, oneModifierFallback.keyCode) + assertEquals(0, oneModifierFallback.metaState) // Multiple modifier fallback. - assertEquals( - keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL, - KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON).keyCode, - KeyEvent.KEYCODE_BACK) + val twoModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL, + KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON) + assertEquals(KeyEvent.KEYCODE_BACK, twoModifierFallback.keyCode) + assertEquals(0, twoModifierFallback.metaState) // No default button, fallback only. - assertEquals( - keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0).keyCode, - KeyEvent.KEYCODE_DPAD_CENTER) + val keyOnlyFallback = + keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0) + assertEquals(KeyEvent.KEYCODE_DPAD_CENTER, keyOnlyFallback.keyCode) + assertEquals(0, keyOnlyFallback.metaState) + + // A key event that is not an exact match for a fallback. Expect a null return. + // E.g. Ctrl + Space -> LanguageSwitch + // Ctrl + Alt + Space -> Ctrl + Alt + Space (No fallback). + val noMatchFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE, + KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON) + assertNull(noMatchFallback) } } diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 49616c30b784..8ac3433033c6 100644 --- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java @@ -765,14 +765,14 @@ public class CrashRecoveryTest { } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } - watchdog.registerHealthObserver(rollbackObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, rollbackObserver); return rollbackObserver; } RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) { setCrashRecoveryPropRescueBootCount(0); RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext)); assertFalse(RescueParty.isRebootPropertySet()); - watchdog.registerHealthObserver(rescuePartyObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, rescuePartyObserver); return rescuePartyObserver; } diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 928e2326498d..1c50cb1b55fd 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -54,7 +54,6 @@ import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.util.AtomicFile; import android.util.LongArrayQueue; -import android.util.Slog; import android.util.Xml; import androidx.test.InstrumentationRegistry; @@ -231,8 +230,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); @@ -248,10 +247,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), SHORT_DURATION, observer2); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE)), @@ -268,8 +267,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); watchdog.unregisterHealthObserver(observer); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -285,10 +284,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); watchdog.unregisterHealthObserver(observer2); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -305,8 +304,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -322,10 +321,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observer2); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -344,14 +343,14 @@ public class PackageWatchdogTest { TestObserver observer = new TestObserver(OBSERVER_NAME_1); // Start observing APP_A - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); // Then advance time half-way moveTimeForwardAndDispatch(SHORT_DURATION / 2); // Start observing APP_A again - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); // Then advance time such that it should have expired were it not for the second observation moveTimeForwardAndDispatch((SHORT_DURATION / 2) + 1); @@ -373,17 +372,17 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog1.registerHealthObserver(observer1, mTestExecutor); - watchdog1.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog1.registerHealthObserver(observer2, mTestExecutor); - watchdog1.startExplicitHealthCheck(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION); + watchdog1.registerHealthObserver(mTestExecutor, observer1); + watchdog1.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog1.registerHealthObserver(mTestExecutor, observer2); + watchdog1.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), SHORT_DURATION, observer2); // Then advance time and run IO Handler so file is saved mTestLooper.dispatchAll(); // Then start a new watchdog PackageWatchdog watchdog2 = createWatchdog(); // Then resume observer1 and observer2 - watchdog2.registerHealthObserver(observer1, mTestExecutor); - watchdog2.registerHealthObserver(observer2, mTestExecutor); + watchdog2.registerHealthObserver(mTestExecutor, observer1); + watchdog2.registerHealthObserver(mTestExecutor, observer2); raiseFatalFailureAndDispatch(watchdog2, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE)), @@ -405,10 +404,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); // Then fail APP_A below the threshold for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) { @@ -434,10 +433,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), SHORT_DURATION, observer1); // Then fail APP_C (not observed) above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -469,8 +468,8 @@ public class PackageWatchdogTest { } }; - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); // Then fail APP_A (different version) above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -499,18 +498,17 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); // Start observing for all impact observers - watchdog.registerHealthObserver(observerNone, mTestExecutor); - watchdog.startExplicitHealthCheck(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D), - SHORT_DURATION); - watchdog.registerHealthObserver(observerHigh, mTestExecutor); - watchdog.startExplicitHealthCheck(observerHigh, Arrays.asList(APP_A, APP_B, APP_C), - SHORT_DURATION); - watchdog.registerHealthObserver(observerMid, mTestExecutor); - watchdog.startExplicitHealthCheck(observerMid, Arrays.asList(APP_A, APP_B), - SHORT_DURATION); - watchdog.registerHealthObserver(observerLow, mTestExecutor); - watchdog.startExplicitHealthCheck(observerLow, Arrays.asList(APP_A), - SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observerNone); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C, APP_D), + SHORT_DURATION, observerNone); + watchdog.registerHealthObserver(mTestExecutor, observerHigh); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C), SHORT_DURATION, + observerHigh); + watchdog.registerHealthObserver(mTestExecutor, observerMid); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), SHORT_DURATION, + observerMid); + watchdog.registerHealthObserver(mTestExecutor, observerLow); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observerLow); // Then fail all apps above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -549,18 +547,17 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); // Start observing for all impact observers - watchdog.registerHealthObserver(observerNone, mTestExecutor); - watchdog.startExplicitHealthCheck(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D), - SHORT_DURATION); - watchdog.registerHealthObserver(observerHigh, mTestExecutor); - watchdog.startExplicitHealthCheck(observerHigh, Arrays.asList(APP_A, APP_B, APP_C), - SHORT_DURATION); - watchdog.registerHealthObserver(observerMid, mTestExecutor); - watchdog.startExplicitHealthCheck(observerMid, Arrays.asList(APP_A, APP_B), - SHORT_DURATION); - watchdog.registerHealthObserver(observerLow, mTestExecutor); - watchdog.startExplicitHealthCheck(observerLow, Arrays.asList(APP_A), - SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observerNone); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C, APP_D), + SHORT_DURATION, observerNone); + watchdog.registerHealthObserver(mTestExecutor, observerHigh); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C), SHORT_DURATION, + observerHigh); + watchdog.registerHealthObserver(mTestExecutor, observerMid); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), SHORT_DURATION, + observerMid); + watchdog.registerHealthObserver(mTestExecutor, observerLow); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observerLow); // Then fail all apps above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -607,10 +604,10 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing for observerFirst and observerSecond with failure handling - watchdog.registerHealthObserver(observerFirst, mTestExecutor); - watchdog.startExplicitHealthCheck(observerFirst, Arrays.asList(APP_A), LONG_DURATION); - watchdog.registerHealthObserver(observerSecond, mTestExecutor); - watchdog.startExplicitHealthCheck(observerSecond, Arrays.asList(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observerFirst); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerFirst); + watchdog.registerHealthObserver(mTestExecutor, observerSecond); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerSecond); // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -673,10 +670,10 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); // Start observing for observerFirst and observerSecond with failure handling - watchdog.registerHealthObserver(observerFirst, mTestExecutor); - watchdog.startExplicitHealthCheck(observerFirst, Arrays.asList(APP_A), LONG_DURATION); - watchdog.registerHealthObserver(observerSecond, mTestExecutor); - watchdog.startExplicitHealthCheck(observerSecond, Arrays.asList(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observerFirst); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerFirst); + watchdog.registerHealthObserver(mTestExecutor, observerSecond); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerSecond); // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -743,10 +740,10 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); // Start observing for observer1 and observer2 with failure handling - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -767,10 +764,10 @@ public class PackageWatchdogTest { PackageHealthObserverImpact.USER_IMPACT_LEVEL_50); // Start observing for observer1 and observer2 with failure handling - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, @@ -800,10 +797,10 @@ public class PackageWatchdogTest { // Start observing with explicit health checks for APP_A and APP_B respectively // with observer1 and observer2 controller.setSupportedPackages(Arrays.asList(APP_A, APP_B)); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), SHORT_DURATION, observer2); // Run handler so requests are dispatched to the controller mTestLooper.dispatchAll(); @@ -819,8 +816,8 @@ public class PackageWatchdogTest { // Observer3 didn't exist when we got the explicit health check above, so // it starts out with a non-passing explicit health check and has to wait for a pass // otherwise it would be notified of APP_A failure on expiry - watchdog.registerHealthObserver(observer3, mTestExecutor); - watchdog.startExplicitHealthCheck(observer3, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer3); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer3); // Then expire observers moveTimeForwardAndDispatch(SHORT_DURATION); @@ -850,9 +847,9 @@ public class PackageWatchdogTest { // Start observing with explicit health checks for APP_A and APP_B controller.setSupportedPackages(Arrays.asList(APP_A, APP_B, APP_C)); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_B), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), LONG_DURATION, observer); // Run handler so requests are dispatched to the controller mTestLooper.dispatchAll(); @@ -888,7 +885,7 @@ public class PackageWatchdogTest { // Then set new supported packages controller.setSupportedPackages(Arrays.asList(APP_C)); // Start observing APP_A and APP_C; only APP_C has support for explicit health checks - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A, APP_C), SHORT_DURATION); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_C), SHORT_DURATION, observer); // Run handler so requests/cancellations are dispatched to the controller mTestLooper.dispatchAll(); @@ -919,8 +916,8 @@ public class PackageWatchdogTest { // package observation duration == LONG_DURATION // health check duration == SHORT_DURATION (set by default in the TestController) controller.setSupportedPackages(Arrays.asList(APP_A)); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observer); // Then APP_A has exceeded health check duration moveTimeForwardAndDispatch(SHORT_DURATION); @@ -951,8 +948,8 @@ public class PackageWatchdogTest { // package observation duration == SHORT_DURATION / 2 // health check duration == SHORT_DURATION (set by default in the TestController) controller.setSupportedPackages(Arrays.asList(APP_A)); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION / 2); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION / 2, observer); // Forward time to expire the observation duration moveTimeForwardAndDispatch(SHORT_DURATION / 2); @@ -1025,7 +1022,7 @@ public class PackageWatchdogTest { // Start observing with failure handling TestObserver observer = new TestObserver(OBSERVER_NAME_1, PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - wd.startExplicitHealthCheck(observer, Collections.singletonList(APP_A), SHORT_DURATION); + wd.startExplicitHealthCheck(Collections.singletonList(APP_A), SHORT_DURATION, observer); // Notify of NetworkStack failure mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A); @@ -1045,7 +1042,7 @@ public class PackageWatchdogTest { // Start observing with failure handling TestObserver observer = new TestObserver(OBSERVER_NAME_1, PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - wd.startExplicitHealthCheck(observer, Collections.singletonList(APP_A), SHORT_DURATION); + wd.startExplicitHealthCheck(Collections.singletonList(APP_A), SHORT_DURATION, observer); // Notify of NetworkStack failure mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A); @@ -1066,8 +1063,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer); // Fail APP_A below the threshold which should not trigger package failures for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) { watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -1095,8 +1092,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), Long.MAX_VALUE, observer); watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1); @@ -1129,8 +1126,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), -1); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), -1, observer); // Note: Don't move too close to the expiration time otherwise the handler will be thrashed // by PackageWatchdog#scheduleNextSyncStateLocked which keeps posting runnables with very // small timeouts. @@ -1152,8 +1149,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), -1); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), -1, observer); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS + 1); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), @@ -1175,8 +1172,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, Arrays.asList(APP_A), Long.MAX_VALUE); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), Long.MAX_VALUE, observer); // Raise 2 failures at t=0 and t=900 respectively watchdog.notifyPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); @@ -1203,10 +1200,10 @@ public class PackageWatchdogTest { TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); - watchdog.registerHealthObserver(observer2, mTestExecutor); - watchdog.startExplicitHealthCheck(observer2, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); + watchdog.registerHealthObserver(mTestExecutor, observer2); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), SHORT_DURATION, observer2); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_CRASH); @@ -1225,8 +1222,8 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); @@ -1246,8 +1243,8 @@ public class PackageWatchdogTest { persistentObserver.setPersistent(true); persistentObserver.setMayObservePackages(true); - watchdog.registerHealthObserver(persistentObserver, mTestExecutor); - watchdog.startExplicitHealthCheck(persistentObserver, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, persistentObserver); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), SHORT_DURATION, persistentObserver); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); @@ -1265,8 +1262,8 @@ public class PackageWatchdogTest { persistentObserver.setPersistent(true); persistentObserver.setMayObservePackages(false); - watchdog.registerHealthObserver(persistentObserver, mTestExecutor); - watchdog.startExplicitHealthCheck(persistentObserver, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, persistentObserver); + watchdog.startExplicitHealthCheck(Arrays.asList(APP_B), SHORT_DURATION, persistentObserver); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); @@ -1277,11 +1274,10 @@ public class PackageWatchdogTest { /** Ensure that boot loop mitigation is done when the number of boots meets the threshold. */ @Test public void testBootLoopDetection_meetsThreshold() { - Slog.w("hrm1243", "I should definitely be here try 1 "); mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { watchdog.noteBoot(); } @@ -1293,7 +1289,7 @@ public class PackageWatchdogTest { public void testBootLoopDetection_meetsThresholdRecoverability() { PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int i = 0; i < 15; i++) { watchdog.noteBoot(); } @@ -1309,7 +1305,7 @@ public class PackageWatchdogTest { public void testBootLoopDetection_doesNotMeetThreshold() { PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; i++) { watchdog.noteBoot(); } @@ -1326,7 +1322,7 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1, PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; i++) { watchdog.noteBoot(); } @@ -1345,8 +1341,8 @@ public class PackageWatchdogTest { bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2); bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - watchdog.registerHealthObserver(bootObserver1, mTestExecutor); - watchdog.registerHealthObserver(bootObserver2, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver1); + watchdog.registerHealthObserver(mTestExecutor, bootObserver2); for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { watchdog.noteBoot(); } @@ -1362,8 +1358,8 @@ public class PackageWatchdogTest { bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2); bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - watchdog.registerHealthObserver(bootObserver1, mTestExecutor); - watchdog.registerHealthObserver(bootObserver2, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver1); + watchdog.registerHealthObserver(mTestExecutor, bootObserver2); for (int i = 0; i < 15; i++) { watchdog.noteBoot(); } @@ -1380,7 +1376,7 @@ public class PackageWatchdogTest { mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int i = 0; i < 4; i++) { for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) { watchdog.noteBoot(); @@ -1403,7 +1399,7 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(); TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1, PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - watchdog.registerHealthObserver(bootObserver, mTestExecutor); + watchdog.registerHealthObserver(mTestExecutor, bootObserver); for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT - 1; j++) { watchdog.noteBoot(); } @@ -1431,8 +1427,8 @@ public class PackageWatchdogTest { public void testNullFailedPackagesList() { PackageWatchdog watchdog = createWatchdog(); TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer1, mTestExecutor); - watchdog.startExplicitHealthCheck(observer1, List.of(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer1); + watchdog.startExplicitHealthCheck(List.of(APP_A), LONG_DURATION, observer1); raiseFatalFailureAndDispatch(watchdog, null, PackageWatchdog.FAILURE_REASON_APP_CRASH); assertThat(observer1.mMitigatedPackages).isEmpty(); @@ -1450,18 +1446,18 @@ public class PackageWatchdogTest { PackageWatchdog watchdog = createWatchdog(testController, true); TestObserver testObserver1 = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(testObserver1, mTestExecutor); - watchdog.startExplicitHealthCheck(testObserver1, List.of(APP_A), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, testObserver1); + watchdog.startExplicitHealthCheck(List.of(APP_A), LONG_DURATION, testObserver1); mTestLooper.dispatchAll(); TestObserver testObserver2 = new TestObserver(OBSERVER_NAME_2); - watchdog.registerHealthObserver(testObserver2, mTestExecutor); - watchdog.startExplicitHealthCheck(testObserver2, List.of(APP_B), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, testObserver2); + watchdog.startExplicitHealthCheck(List.of(APP_B), LONG_DURATION, testObserver2); mTestLooper.dispatchAll(); TestObserver testObserver3 = new TestObserver(OBSERVER_NAME_3); - watchdog.registerHealthObserver(testObserver3, mTestExecutor); - watchdog.startExplicitHealthCheck(testObserver3, List.of(APP_C), LONG_DURATION); + watchdog.registerHealthObserver(mTestExecutor, testObserver3); + watchdog.startExplicitHealthCheck(List.of(APP_C), LONG_DURATION, testObserver3); mTestLooper.dispatchAll(); watchdog.unregisterHealthObserver(testObserver1); @@ -1493,15 +1489,15 @@ public class PackageWatchdogTest { public void testFailureHistoryIsPreserved() { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, List.of(APP_A), SHORT_DURATION); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(List.of(APP_A), SHORT_DURATION, observer); for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) { watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); } mTestLooper.dispatchAll(); assertThat(observer.mMitigatedPackages).isEmpty(); - watchdog.startExplicitHealthCheck(observer, List.of(APP_A), LONG_DURATION); + watchdog.startExplicitHealthCheck(List.of(APP_A), LONG_DURATION, observer); watchdog.notifyPackageFailure(List.of(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); @@ -1516,9 +1512,9 @@ public class PackageWatchdogTest { public void testMitigationSlidingWindow() { PackageWatchdog watchdog = createWatchdog(); TestObserver observer = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(observer, mTestExecutor); - watchdog.startExplicitHealthCheck(observer, List.of(APP_A), - PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS * 2); + watchdog.registerHealthObserver(mTestExecutor, observer); + watchdog.startExplicitHealthCheck(List.of(APP_A), + PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS * 2, observer); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp index 44aa4028c916..370c0048d9a9 100644 --- a/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp +++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp @@ -38,6 +38,9 @@ android_test { ], test_suites: [ "general-tests", + // This is an equivalent of general-tests for automotive. + // It helps manage the build time on automotive branches. + "automotive-general-tests", ], sdk_version: "test_current", diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp index 5e0f87f0dcaf..60c4bf5c4131 100644 --- a/tools/aapt/Package.cpp +++ b/tools/aapt/Package.cpp @@ -292,13 +292,12 @@ bool processFile(Bundle* bundle, ZipFile* zip, } if (!hasData) { const String8& srcName = file->getSourceFile(); - time_t fileModWhen; - fileModWhen = getFileModDate(srcName.c_str()); - if (fileModWhen == (time_t) -1) { // file existence tested earlier, - return false; // not expecting an error here + auto fileModWhen = getFileModDate(srcName.c_str()); + if (fileModWhen == kInvalidModDate) { // file existence tested earlier, + return false; // not expecting an error here } - - if (fileModWhen > entry->getModWhen()) { + + if (toTimeT(fileModWhen) > entry->getModWhen()) { // mark as deleted so add() will succeed if (bundle->getVerbose()) { printf(" (removing old '%s')\n", storageName.c_str()); diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 661df4d0fe33..e24fe07f959b 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -683,8 +683,6 @@ class ChunkPrinter { item->PrettyPrint(printer_); printer_->Print(")"); } - - printer_->Print("\n"); } void PrintQualifiers(uint32_t qualifiers) const { @@ -763,11 +761,13 @@ class ChunkPrinter { bool PrintTableType(const ResTable_type* chunk) { printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id))); - printer_->Print(StringPrintf( - " name: %s", - android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1) - .c_str())); + const auto name = + android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1); + printer_->Print(StringPrintf(" name: %s", name.c_str())); printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags))); + printer_->Print(android::util::DeviceToHost32(chunk->flags) & ResTable_type::FLAG_SPARSE + ? " (SPARSE)" + : " (DENSE)"); printer_->Print( StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount))); printer_->Print( @@ -777,8 +777,7 @@ class ChunkPrinter { config.copyFromDtoH(chunk->config); printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str())); - const ResourceType* type = ParseResourceType( - android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1)); + const ResourceType* type = ParseResourceType(name); printer_->Indent(); @@ -817,11 +816,8 @@ class ChunkPrinter { for (size_t i = 0; i < map_entry_count; i++) { PrintResValue(&(maps[i].value), config, type); - printer_->Print(StringPrintf( - " name: %s name-id:%d\n", - android::util::GetString(key_pool_, android::util::DeviceToHost32(maps[i].name.ident)) - .c_str(), - android::util::DeviceToHost32(maps[i].name.ident))); + printer_->Print(StringPrintf(" name-id: 0x%08x\n", + android::util::DeviceToHost32(maps[i].name.ident))); } } else { printer_->Print("\n"); @@ -829,6 +825,8 @@ class ChunkPrinter { // Print the value of the entry Res_value value = entry->value(); PrintResValue(&value, config, type); + + printer_->Print("\n"); } printer_->Undent(); |