diff options
496 files changed, 10431 insertions, 5215 deletions
diff --git a/Android.bp b/Android.bp index 2318f7bbf73a..c89917975e8e 100644 --- a/Android.bp +++ b/Android.bp @@ -551,17 +551,25 @@ java_library { java_library { name: "framework-annotation-proc", - srcs: [":framework-all-sources"], + srcs: [ + ":framework-all-sources", + "core/java/**/*.logtags", + ], + sdk_version: "core_platform", libs: [ "app-compat-annotations", + "ext", + "icing-java-proto-lite", "unsupportedappusage", ], + installable: false, plugins: [ "unsupportedappusage-annotation-processor", "compat-changeid-annotation-processor", ], static_libs: [ + "framework-internal-utils", "exoplayer2-extractor", "android.hardware.wifi-V1.0-java-constants", ] diff --git a/apex/Android.bp b/apex/Android.bp index abebfa39fada..362cf95b3832 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -29,6 +29,16 @@ mainline_stubs_args = // TODO: remove this server classes are cleaned up. mainline_stubs_args += "--hide-package com.android.server " +priv_apps = " " + + "--show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "\\) " + +module_libs = " " + + " --show-annotation android.annotation.SystemApi\\(" + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + + "\\) " + stubs_defaults { name: "framework-module-stubs-defaults-publicapi", args: mainline_stubs_args, @@ -37,36 +47,23 @@ stubs_defaults { stubs_defaults { name: "framework-module-stubs-defaults-systemapi", - args: mainline_stubs_args + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + - "process=android.annotation.SystemApi.Process.ALL\\) ", + args: mainline_stubs_args + priv_apps, installable: false, } +// The defaults for module_libs comes in two parts - defaults for API checks +// and defaults for stub generation. This is because we want the API txt +// files to *only* include the module_libs_api, but the stubs to include +// module_libs_api as well as priv_apps. + stubs_defaults { - name: "framework-module-stubs-defaults-module_apps_api", - args: mainline_stubs_args + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + - "process=android.annotation.SystemApi.Process.ALL\\) " + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.MODULE_APPS," + - "process=android.annotation.SystemApi.Process.ALL\\) ", + name: "framework-module-api-defaults-module_libs_api", + args: mainline_stubs_args + module_libs, installable: false, } stubs_defaults { name: "framework-module-stubs-defaults-module_libs_api", - args: mainline_stubs_args + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + - "process=android.annotation.SystemApi.Process.ALL\\) " + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.MODULE_APPS," + - "process=android.annotation.SystemApi.Process.ALL\\) " + - " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + - "process=android.annotation.SystemApi.Process.ALL\\) ", + args: mainline_stubs_args + module_libs + priv_apps, installable: false, } diff --git a/api/current.txt b/api/current.txt index 5ac58d043660..515df6d8b654 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14860,10 +14860,11 @@ package android.graphics { method public void offset(int, int); method public void set(@NonNull android.graphics.Outline); method public void setAlpha(@FloatRange(from=0.0, to=1.0) float); - method public void setConvexPath(@NonNull android.graphics.Path); + method @Deprecated public void setConvexPath(@NonNull android.graphics.Path); method public void setEmpty(); method public void setOval(int, int, int, int); method public void setOval(@NonNull android.graphics.Rect); + method public void setPath(@NonNull android.graphics.Path); method public void setRect(int, int, int, int); method public void setRect(@NonNull android.graphics.Rect); method public void setRoundRect(int, int, int, int, float); @@ -39564,7 +39565,7 @@ package android.provider { protected static interface ContactsContract.RawContactsColumns { field public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set"; field public static final String AGGREGATION_MODE = "aggregation_mode"; - field @Deprecated public static final String BACKUP_ID = "backup_id"; + field public static final String BACKUP_ID = "backup_id"; field public static final String CONTACT_ID = "contact_id"; field public static final String DATA_SET = "data_set"; field public static final String DELETED = "deleted"; @@ -47295,6 +47296,7 @@ package android.telephony { public final class PreciseDataConnectionState implements android.os.Parcelable { method public int describeContents(); + method @Nullable public android.telephony.data.ApnSetting getApnSetting(); method public int getLastCauseCode(); method @Nullable public android.net.LinkProperties getLinkProperties(); method public int getNetworkType(); diff --git a/api/module-app-current.txt b/api/module-app-current.txt index dadbd79e0e8d..d802177e249b 100644 --- a/api/module-app-current.txt +++ b/api/module-app-current.txt @@ -1,21 +1 @@ // Signature format: 2.0 -package android.app { - - public final class NotificationChannel implements android.os.Parcelable { - method public void setBlockableSystem(boolean); - } - -} - -package android.provider { - - public final class DocumentsContract { - method @NonNull public static android.net.Uri buildDocumentUriAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); - } - - public static final class Settings.Global extends android.provider.Settings.NameValueTable { - field public static final String COMMON_CRITERIA_MODE = "common_criteria_mode"; - } - -} - diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index 1a2cb74a5aad..d11801b359c8 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -6,7 +6,7 @@ package android.app.timedetector { method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); method public int describeContents(); method @NonNull public java.util.List<java.lang.String> getDebugInfo(); - method public int getPhoneId(); + method public int getSlotIndex(); method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR; @@ -34,8 +34,8 @@ package android.app.timezonedetector { method public int describeContents(); method @NonNull public java.util.List<java.lang.String> getDebugInfo(); method public int getMatchType(); - method public int getPhoneId(); method public int getQuality(); + method public int getSlotIndex(); method @Nullable public String getZoneId(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR; diff --git a/api/system-current.txt b/api/system-current.txt index ed9f1341a2d0..8630b36f1595 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -665,6 +665,7 @@ package android.app { method public int getUserLockedFields(); method public boolean isDeleted(); method public void populateFromXml(org.xmlpull.v1.XmlPullParser); + method public void setBlockableSystem(boolean); method public org.json.JSONObject toJson() throws org.json.JSONException; method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException; field public static final int USER_LOCKED_SOUND = 32; // 0x20 @@ -2452,8 +2453,8 @@ package android.hardware { package android.hardware.biometrics { public static interface BiometricManager.Authenticators { - field public static final int BIOMETRIC_CONVENIENCE = 4095; // 0xfff - field public static final int EMPTY_SET = 0; // 0x0 + field @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static final int BIOMETRIC_CONVENIENCE = 4095; // 0xfff + field @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static final int EMPTY_SET = 0; // 0x0 } } @@ -5377,7 +5378,7 @@ package android.media.tv.tuner.frontend { public static class Atsc3FrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder> { method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings build(); method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setBandwidth(int); - method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setDemodOutputFormat(byte); + method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setDemodOutputFormat(int); method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setPlpSettings(@NonNull android.media.tv.tuner.frontend.Atsc3PlpSettings[]); } @@ -5431,7 +5432,7 @@ package android.media.tv.tuner.frontend { public class DvbcFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder builder(@NonNull android.content.Context); - method public byte getAnnex(); + method public int getAnnex(); method public long getFec(); method public int getModulation(); method public int getOuterFec(); @@ -5459,7 +5460,7 @@ package android.media.tv.tuner.frontend { public static class DvbcFrontendSettings.Builder extends android.media.tv.tuner.frontend.FrontendSettings.Builder<android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder> { method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings build(); - method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(byte); + method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(int); method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFec(long); method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setModulation(int); method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int); @@ -7509,20 +7510,16 @@ package android.net.wifi { @Deprecated public class WifiConfiguration implements android.os.Parcelable { method @Deprecated public int getAuthType(); - method @Deprecated @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment(); method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration(); method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus(); method @Deprecated @NonNull public String getPrintableSsid(); - method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings(); method @Deprecated public int getRecentFailureReason(); - method @Deprecated @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration(); method @Deprecated public boolean hasNoInternetAccess(); method @Deprecated public boolean isEphemeral(); method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo); method @Deprecated public boolean isNoInternetAccessExpected(); method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration); method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus); - method @Deprecated public void setProxy(@NonNull android.net.IpConfiguration.ProxySettings, @NonNull android.net.ProxyInfo); field @Deprecated public static final int AP_BAND_2GHZ = 0; // 0x0 field @Deprecated public static final int AP_BAND_5GHZ = 1; // 0x1 field @Deprecated public static final int AP_BAND_ANY = -1; // 0xffffffff @@ -7564,11 +7561,11 @@ package android.net.wifi { @Deprecated public static class WifiConfiguration.NetworkSelectionStatus { method @Deprecated public int getDisableReasonCounter(int); method @Deprecated public long getDisableTime(); - method @Deprecated public boolean getHasEverConnected(); method @Deprecated @Nullable public static String getNetworkDisableReasonString(int); method @Deprecated public int getNetworkSelectionDisableReason(); method @Deprecated public int getNetworkSelectionStatus(); method @Deprecated @NonNull public String getNetworkStatusString(); + method @Deprecated public boolean hasEverConnected(); method @Deprecated public boolean isNetworkEnabled(); method @Deprecated public boolean isNetworkPermanentlyDisabled(); field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1 @@ -7578,10 +7575,10 @@ package android.net.wifi { field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7 field @Deprecated public static final int DISABLED_BY_WRONG_PASSWORD = 8; // 0x8 field @Deprecated public static final int DISABLED_DHCP_FAILURE = 3; // 0x3 + field @Deprecated public static final int DISABLED_NONE = 0; // 0x0 field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6 field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4 field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa - field @Deprecated public static final int NETWORK_SELECTION_ENABLE = 0; // 0x0 field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0 field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2 field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1 @@ -8909,13 +8906,13 @@ package android.os { public class UpdateEngine { ctor public UpdateEngine(); - method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]); + method @NonNull @WorkerThread public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]); method public void applyPayload(String, long, long, String[]); method public void applyPayload(@NonNull android.content.res.AssetFileDescriptor, @NonNull String[]); method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler); method public boolean bind(android.os.UpdateEngineCallback); method public void cancel(); - method public int cleanupAppliedPayload(); + method @WorkerThread public int cleanupAppliedPayload(); method public void resetStatus(); method public void resume(); method public void suspend(); @@ -8924,8 +8921,8 @@ package android.os { } public static final class UpdateEngine.AllocateSpaceResult { - method public int errorCode(); - method public long freeSpaceRequired(); + method public int getErrorCode(); + method public long getFreeSpaceRequired(); } public static final class UpdateEngine.ErrorCodeConstants { @@ -9169,7 +9166,12 @@ package android.os.storage { method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException; method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException; method public static boolean hasIsolatedStorage(); + method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException; field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2 + field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1 + field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0 + field public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; // 0x3 } public final class StorageVolume implements android.os.Parcelable { @@ -9217,7 +9219,7 @@ package android.permission { } public final class PermissionManager { - method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion(); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions(); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); @@ -9225,7 +9227,7 @@ package android.permission { method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int); + method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int); method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String); } @@ -9455,6 +9457,7 @@ package android.provider { } public final class DocumentsContract { + method @NonNull public static android.net.Uri buildDocumentUriAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method public static boolean isManageMode(@NonNull android.net.Uri); method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri); field public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS"; @@ -9615,6 +9618,7 @@ package android.provider { field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages"; field public static final String CARRIER_APP_NAMES = "carrier_app_names"; field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist"; + field public static final String COMMON_CRITERIA_MODE = "common_criteria_mode"; field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; field public static final String DEVICE_DEMO_MODE = "device_demo_mode"; field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data"; diff --git a/api/test-current.txt b/api/test-current.txt index fda3ab4084a8..c8d746b44a15 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -767,6 +767,7 @@ package android.content { method public void setAutofillOptions(@Nullable android.content.AutofillOptions); method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); + field public static final String APP_INTEGRITY_SERVICE = "app_integrity"; field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; @@ -792,6 +793,60 @@ package android.content { } +package android.content.integrity { + + public class AppIntegrityManager { + method @NonNull public android.content.integrity.RuleSet getCurrentRuleSet(); + method @NonNull public String getCurrentRuleSetProvider(); + method @NonNull public String getCurrentRuleSetVersion(); + method public void updateRuleSet(@NonNull android.content.integrity.RuleSet, @NonNull android.content.IntentSender); + field public static final String EXTRA_STATUS = "android.content.integrity.extra.STATUS"; + field public static final int STATUS_FAILURE = 1; // 0x1 + field public static final int STATUS_SUCCESS = 0; // 0x0 + } + + public abstract class IntegrityFormula { + method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(@NonNull String); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(boolean); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThan(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThanOrEquals(long); + method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula); + field @NonNull public static final android.content.integrity.IntegrityFormula APP_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PACKAGE_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PRE_INSTALLED; + field @NonNull public static final android.content.integrity.IntegrityFormula VERSION_CODE; + } + + public final class Rule implements android.os.Parcelable { + ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int); + method public int describeContents(); + method public int getEffect(); + method @NonNull public android.content.integrity.IntegrityFormula getFormula(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR; + field public static final int DENY = 0; // 0x0 + field public static final int FORCE_ALLOW = 1; // 0x1 + } + + public class RuleSet { + method @NonNull public java.util.List<android.content.integrity.Rule> getRules(); + method @NonNull public String getVersion(); + } + + public static class RuleSet.Builder { + ctor public RuleSet.Builder(); + method @NonNull public android.content.integrity.RuleSet.Builder addRules(@NonNull java.util.List<android.content.integrity.Rule>); + method @NonNull public android.content.integrity.RuleSet build(); + method @NonNull public android.content.integrity.RuleSet.Builder setVersion(@NonNull String); + } + +} + package android.content.pm { public class ActivityInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable { @@ -2713,9 +2768,9 @@ package android.permission { } public final class PermissionManager { - method @IntRange(from=0) @RequiresPermission("android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY") public int getRuntimePermissionsVersion(); + method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions(); - method @RequiresPermission("android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY") public void setRuntimePermissionsVersion(@IntRange(from=0) int); + method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int); } public static final class PermissionManager.SplitPermissionInfo { @@ -4924,6 +4979,11 @@ package android.view { method public abstract String asyncImpl() default ""; } + public class SurfaceControlViewHost { + method public void addView(@NonNull android.view.View, android.view.WindowManager.LayoutParams); + method public void relayout(android.view.WindowManager.LayoutParams); + } + @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { method public android.view.View getTooltipView(); method public boolean isAutofilled(); diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 520366f518ab..a1278f358380 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -42,10 +42,10 @@ #include <android-base/properties.h> +#include <ui/DisplayConfig.h> #include <ui/PixelFormat.h> #include <ui/Rect.h> #include <ui/Region.h> -#include <ui/DisplayInfo.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> @@ -283,16 +283,19 @@ status_t BootAnimation::readyToRun() { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); if (mDisplayToken == nullptr) - return -1; + return NAME_NOT_FOUND; - DisplayInfo dinfo; - status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo); - if (status) - return -1; + DisplayConfig displayConfig; + const status_t error = + SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig); + if (error != NO_ERROR) + return error; + + const ui::Size& resolution = displayConfig.resolution; // create the native surface sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), - dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565); + resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565); SurfaceComposerClient::Transaction t; diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index bd4397afaeb7..2237bf2b2acb 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -122,7 +122,6 @@ cc_defaults { "libbase", "libcutils", "liblog", - "libplatformprotos", "libprotoutil", "libstatslog", "libstatssocket", diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp index 109785f649e4..5b75b97a0764 100644 --- a/cmds/statsd/src/HashableDimensionKey.cpp +++ b/cmds/statsd/src/HashableDimensionKey.cpp @@ -16,8 +16,6 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include <mutex> - #include "HashableDimensionKey.h" #include "FieldValue.h" diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 34818145a922..879b3c3e52aa 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -20,11 +20,7 @@ #include "StatsLogProcessor.h" #include <android-base/file.h> -#include <dirent.h> #include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> -#include <log/log_event_list.h> -#include <utils/Errors.h> -#include <utils/SystemClock.h> #include "android-base/stringprintf.h" #include "atoms_info.h" @@ -47,8 +43,6 @@ using android::util::FIELD_TYPE_INT64; using android::util::FIELD_TYPE_MESSAGE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; -using std::make_unique; -using std::unique_ptr; using std::vector; namespace android { diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 05281f79592f..8a8c1e6ff0ac 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -27,12 +27,10 @@ #include "subscriber/SubscriberReporter.h" #include <android-base/file.h> -#include <android-base/stringprintf.h> #include <android-base/strings.h> #include <binder/IPCThreadState.h> #include <binder/PermissionController.h> #include <cutils/multiuser.h> -#include <dirent.h> #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h> #include <frameworks/base/cmds/statsd/src/uid_data.pb.h> #include <private/android_filesystem_config.h> @@ -41,17 +39,13 @@ #include <stdlib.h> #include <sys/system_properties.h> #include <unistd.h> -#include <utils/Looper.h> #include <utils/String16.h> -#include <chrono> using namespace android; using android::base::StringPrintf; using android::util::FIELD_COUNT_REPEATED; -using android::util::FIELD_TYPE_INT64; using android::util::FIELD_TYPE_MESSAGE; -using android::util::ProtoReader; namespace android { namespace os { diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index f2079d9f278f..3bfaa9842950 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -37,11 +37,9 @@ #include <binder/ParcelFileDescriptor.h> #include <utils/Looper.h> -#include <deque> #include <mutex> using namespace android; -using namespace android::base; using namespace android::binder; using namespace android::frameworks::stats::V1_0; using namespace android::os; diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h index bca858e67f13..219695ef5e43 100644 --- a/cmds/statsd/src/anomaly/AlarmMonitor.h +++ b/cmds/statsd/src/anomaly/AlarmMonitor.h @@ -21,8 +21,6 @@ #include <android/os/IStatsCompanionService.h> #include <utils/RefBase.h> -#include <queue> -#include <set> #include <unordered_set> #include <vector> diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h index e9414735b82b..794ee988ef55 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.h +++ b/cmds/statsd/src/anomaly/AnomalyTracker.h @@ -16,8 +16,6 @@ #pragma once -#include <memory> // unique_ptr - #include <stdlib.h> #include <gtest/gtest_prod.h> diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp index 4c30c4cb223c..5a4a41d01de6 100644 --- a/cmds/statsd/src/anomaly/subscriber_util.cpp +++ b/cmds/statsd/src/anomaly/subscriber_util.cpp @@ -17,10 +17,6 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include <android/os/IIncidentManager.h> -#include <android/os/IncidentReportArgs.h> -#include <binder/IServiceManager.h> - #include "external/Perfetto.h" #include "subscriber/IncidentdReporter.h" #include "subscriber/SubscriberReporter.h" diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index 946c55087005..9c875ba7502d 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -24,46 +24,75 @@ option java_outer_classname = "AtomFieldOptions"; import "google/protobuf/descriptor.proto"; enum StateField { - // Default value for fields that are not primary or exclusive state. + // Default value for fields that are not a primary or exclusive state field. STATE_FIELD_UNSET = 0; // Fields that represent the key that the state belongs to. - PRIMARY = 1; + // Used on simple proto fields. Do not use on attribution chains. + PRIMARY_FIELD = 1; // The field that represents the state. It's an exclusive state. - EXCLUSIVE = 2; - + EXCLUSIVE_STATE = 2; + // Used on an attribution chain field to indicate that the first uid is the + // primary field. PRIMARY_FIELD_FIRST_UID = 3; } -// Used to annotate an atom that reprsents a state change. A state change atom must have exactly ONE -// exclusive state field, and any number of primary key fields. -// For example, -// message UidProcessStateChanged { -// optional int32 uid = 1 [(state_field_option).option = PRIMARY]; -// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE]; +// Used to annotate an atom that represents a state change. A state change atom must have exactly +// ONE exclusive state field, and any number of primary key fields. For example, message +// UidProcessStateChanged { +// optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD]; +// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = +// EXCLUSIVE_STATE]; // } -// Each of this UidProcessStateChanged atom represents a state change for a specific uid. +// Each UidProcessStateChanged atom event represents a state change for a specific uid. // A new state automatically overrides the previous state. // -// If the atom has 2 or more primary fields, it means the combination of the primary fields are -// the primary key. +// If the atom has 2 or more primary fields, it means the combination of the +// primary fields are the primary key. // For example: // message ThreadStateChanged { -// optional int32 pid = 1 [(state_field_option).option = PRIMARY]; -// optional int32 tid = 2 [(state_field_option).option = PRIMARY]; -// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE]; +// optional int32 pid = 1 [(state_field_option).option = PRIMARY_FIELD]; +// optional int32 tid = 2 [(state_field_option).option = PRIMARY_FIELD]; +// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE_STATE]; // } // // Sometimes, there is no primary key field, when the state is GLOBAL. // For example, -// // message ScreenStateChanged { -// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE]; +// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = +// EXCLUSIVE_STATE]; // } // -// Only fields of primary types can be annotated. AttributionNode cannot be primary keys (and they -// usually are not). +// For state atoms with attribution chain, sometimes the primary key is the first uid in the chain. +// For example: +// message AudioStateChanged { +// repeated AttributionNode attribution_node = 1 +// [(stateFieldOption).option = PRIMARY_KEY_FIRST_UID]; +// +// enum State { +// OFF = 0; +// ON = 1; +// // RESET indicates all audio stopped. Used when it (re)starts (e.g. after it crashes). +// RESET = 2; +// } +// optional State state = 2 [(stateFieldOption).option = EXCLUSIVE_STATE]; +// } message StateAtomFieldOption { optional StateField option = 1 [default = STATE_FIELD_UNSET]; + + // Note: We cannot annotate directly on the enums because many enums are imported from other + // proto files in the platform. proto-lite cc library does not support annotations unfortunately + + // Knowing the default state value allows state trackers to remove entries that become the + // default state. If there is no default value specified, the default value is unknown, and all + // states will be tracked in memory. + optional int32 default_state_value = 2; + + // A reset state signals all states go to default value. For example, BLE reset means all active + // BLE scans are to be turned off. + optional int32 reset_state_value = 3; + + // If the state change needs to count nesting. + optional bool nested = 4 [default = true]; } // Used to generate StatsLog.write APIs. diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 12058cae1a2a..cc05dbb0639c 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -381,8 +381,8 @@ message Atom { NotificationReported notification_reported = 244; NotificationPanelReported notification_panel_reported = 245; NotificationChannelModified notification_panel_modified = 246; - IntegrityCheckResultReported integrity_check_result_reported = 247; - IntegrityRulesPushed integrity_rules_pushed = 248; + IntegrityCheckResultReported integrity_check_result_reported = 247 [(module) = "framework"]; + IntegrityRulesPushed integrity_rules_pushed = 248 [(module) = "framework"]; CellBroadcastMessageReported cb_message_reported = 249 [(module) = "cellbroadcast"]; CellBroadcastMessageError cb_message_error = @@ -466,7 +466,7 @@ message Atom { DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067 [(module) = "framework"]; GraphicsStats graphics_stats = 10068; - RuntimeAppOpsAccess runtime_app_ops_access = 10069; + RuntimeAppOpAccess runtime_app_op_access = 10069 [(module) = "framework"]; IonHeapSize ion_heap_size = 10070 [(module) = "framework"]; } @@ -563,7 +563,8 @@ message ThermalThrottlingStateChanged { */ message ScreenStateChanged { // New screen state, from frameworks/base/core/proto/android/view/enums.proto. - optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE]; + optional android.view.DisplayStateEnum state = 1 + [(state_field_option).option = EXCLUSIVE_STATE, (state_field_option).nested = false]; } /** @@ -574,10 +575,11 @@ message ScreenStateChanged { * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java */ message UidProcessStateChanged { - optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true]; + optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD, (is_uid) = true]; // The state, from frameworks/base/core/proto/android/app/enums.proto. - optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE]; + optional android.app.ProcessStateEnum state = 2 + [(state_field_option).option = EXCLUSIVE_STATE, (state_field_option).nested = false]; } /** @@ -609,7 +611,7 @@ message ActivityManagerSleepStateChanged { ASLEEP = 1; AWAKE = 2; } - optional State state = 1 [(state_field_option).option = EXCLUSIVE]; + optional State state = 1 [(state_field_option).option = EXCLUSIVE_STATE]; } /** @@ -628,7 +630,7 @@ message MemoryFactorStateChanged { CRITICAL = 4; // critical memory. } - optional State factor = 1 [(state_field_option).option = EXCLUSIVE]; + optional State factor = 1 [(state_field_option).option = EXCLUSIVE_STATE]; } /** @@ -790,7 +792,8 @@ message ProcessLifeCycleStateChanged { * packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java */ message BleScanStateChanged { - repeated AttributionNode attribution_node = 1; + repeated AttributionNode attribution_node = 1 + [(state_field_option).option = PRIMARY_FIELD_FIRST_UID]; enum State { OFF = 0; @@ -798,14 +801,19 @@ message BleScanStateChanged { // RESET indicates all ble stopped. Used when it (re)starts (e.g. after it crashes). RESET = 2; } - optional State state = 2; + optional State state = 2 [ + (state_field_option).option = EXCLUSIVE_STATE, + (state_field_option).default_state_value = 0 /* State.OFF */, + (state_field_option).reset_state_value = 2 /* State.RESET */, + (state_field_option).nested = true + ]; // Does the scan have a filter. - optional bool is_filtered = 3; + optional bool is_filtered = 3 [(state_field_option).option = PRIMARY_FIELD]; // Whether the scan is a CALLBACK_TYPE_FIRST_MATCH scan. Called 'background' scan internally. - optional bool is_first_match = 4; + optional bool is_first_match = 4 [(state_field_option).option = PRIMARY_FIELD]; // Whether the scan set to piggy-back off the results of other scans (SCAN_MODE_OPPORTUNISTIC). - optional bool is_opportunistic = 5; + optional bool is_opportunistic = 5 [(state_field_option).option = PRIMARY_FIELD]; } /** @@ -1029,11 +1037,11 @@ message WakelockStateChanged { // The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock. // From frameworks/base/core/proto/android/os/enums.proto. - optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).option = PRIMARY]; + optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).option = PRIMARY_FIELD]; ; // The wakelock tag (Called tag in the Java API, sometimes name elsewhere). - optional string tag = 3 [(state_field_option).option = PRIMARY]; + optional string tag = 3 [(state_field_option).option = PRIMARY_FIELD]; enum State { RELEASE = 0; @@ -1041,7 +1049,11 @@ message WakelockStateChanged { CHANGE_RELEASE = 2; CHANGE_ACQUIRE = 3; } - optional State state = 4 [(state_field_option).option = EXCLUSIVE]; + optional State state = 4 [ + (state_field_option).option = EXCLUSIVE_STATE, + (state_field_option).default_state_value = 0, + (state_field_option).nested = true + ]; } /** @@ -3225,9 +3237,9 @@ message PictureInPictureStateChanged { * services/core/java/com/android/server/wm/Session.java */ message OverlayStateChanged { - optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true]; + optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD, (is_uid) = true]; - optional string package_name = 2 [(state_field_option).option = PRIMARY]; + optional string package_name = 2 [(state_field_option).option = PRIMARY_FIELD]; optional bool using_alert_window = 3; @@ -3235,7 +3247,11 @@ message OverlayStateChanged { ENTERED = 1; EXITED = 2; } - optional State state = 4 [(state_field_option).option = EXCLUSIVE]; + optional State state = 4 [ + (state_field_option).option = EXCLUSIVE_STATE, + (state_field_option).nested = false, + (state_field_option).default_state_value = 2 + ]; } /* @@ -3401,7 +3417,7 @@ message LmkKillOccurred { */ message AppDied { // timestamp(elapsedRealtime) of record creation - optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE]; + optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE_STATE]; } /** @@ -3921,7 +3937,7 @@ message PrivacyIndicatorsInteracted { DIALOG_LINE_ITEM = 5; } - optional Type type = 1 [(state_field_option).option = EXCLUSIVE]; + optional Type type = 1 [(state_field_option).option = EXCLUSIVE_STATE]; // Used if the type is LINE_ITEM optional string package_name = 2; @@ -8132,15 +8148,15 @@ message GraphicsStats { /** * Message related to dangerous (runtime) app ops access */ -message RuntimeAppOpsAccess { +message RuntimeAppOpAccess { // Uid of the package accessing app op optional int32 uid = 1 [(is_uid) = true]; // Name of the package accessing app op optional string package_name = 2; - // operation id; maps to the OP_* constants in AppOpsManager.java - optional int32 op_id = 3; + // operation string id per OPSTR_ constants in AppOpsManager.java + optional string op = 3; // feature id; provided by developer when accessing related API, limited at 50 chars by API. // Features must be provided through manifest using <feature> tag available in R and above. diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp index 69aae3d1e31c..2d7f912dac84 100644 --- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp +++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp @@ -18,15 +18,10 @@ #include "Log.h" #include "CombinationConditionTracker.h" -#include <log/logprint.h> - namespace android { namespace os { namespace statsd { -using std::map; -using std::string; -using std::unique_ptr; using std::unordered_map; using std::vector; diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h index e94ea6586f05..26de88860ab4 100644 --- a/cmds/statsd/src/condition/ConditionTracker.h +++ b/cmds/statsd/src/condition/ConditionTracker.h @@ -21,10 +21,8 @@ #include "matchers/LogMatchingTracker.h" #include "matchers/matcher_util.h" -#include <log/logprint.h> #include <utils/RefBase.h> -#include <unordered_set> #include <unordered_map> namespace android { diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp index 4f44a69ba980..c542032b48ea 100644 --- a/cmds/statsd/src/condition/ConditionWizard.cpp +++ b/cmds/statsd/src/condition/ConditionWizard.cpp @@ -14,14 +14,11 @@ * limitations under the License. */ #include "ConditionWizard.h" -#include <unordered_set> namespace android { namespace os { namespace statsd { -using std::map; -using std::string; using std::vector; ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters, diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index 0c92149f4c96..61760f3e29b2 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -24,11 +24,7 @@ namespace android { namespace os { namespace statsd { -using std::map; -using std::string; -using std::unique_ptr; using std::unordered_map; -using std::vector; SimpleConditionTracker::SimpleConditionTracker( const ConfigKey& key, const int64_t& id, const int index, diff --git a/cmds/statsd/src/condition/StateConditionTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp index 7f3eeddba831..d19a1761ac00 100644 --- a/cmds/statsd/src/condition/StateConditionTracker.cpp +++ b/cmds/statsd/src/condition/StateConditionTracker.cpp @@ -23,8 +23,6 @@ namespace android { namespace os { namespace statsd { -using std::string; -using std::unordered_set; using std::vector; StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index, diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp index 35e03e45c785..60b8c53e91e1 100644 --- a/cmds/statsd/src/condition/condition_util.cpp +++ b/cmds/statsd/src/condition/condition_util.cpp @@ -18,11 +18,6 @@ #include "condition_util.h" -#include <log/event_tag_map.h> -#include <log/log_event_list.h> -#include <log/logprint.h> -#include <utils/Errors.h> -#include <unordered_map> #include "../matchers/matcher_util.h" #include "ConditionTracker.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" @@ -32,9 +27,6 @@ namespace android { namespace os { namespace statsd { -using std::set; -using std::string; -using std::unordered_map; using std::vector; diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h index 54e77701b7dc..dcd5e52feefd 100644 --- a/cmds/statsd/src/config/ConfigListener.h +++ b/cmds/statsd/src/config/ConfigListener.h @@ -19,14 +19,12 @@ #include "config/ConfigKey.h" #include <utils/RefBase.h> -#include <string> namespace android { namespace os { namespace statsd { using android::RefBase; -using std::string; /** * Callback for different subsystems inside statsd to implement to find out diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index 972adf7d4d05..986955bc5f39 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -25,8 +25,6 @@ #include "stats_util.h" #include "stats_log_util.h" -#include <android-base/file.h> -#include <dirent.h> #include <stdio.h> #include <vector> #include "android-base/stringprintf.h" @@ -35,9 +33,7 @@ namespace android { namespace os { namespace statsd { -using std::map; using std::pair; -using std::set; using std::string; using std::vector; diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h index 88e864a2520b..2095173e8959 100644 --- a/cmds/statsd/src/config/ConfigManager.h +++ b/cmds/statsd/src/config/ConfigManager.h @@ -20,9 +20,7 @@ #include "config/ConfigListener.h" #include <android/os/IPendingIntentRef.h> -#include <map> #include <mutex> -#include <set> #include <string> #include <stdio.h> diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp index 0c4c3301e61e..85b660efc956 100644 --- a/cmds/statsd/src/external/Perfetto.cpp +++ b/cmds/statsd/src/external/Perfetto.cpp @@ -21,12 +21,8 @@ #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert #include <android-base/unique_fd.h> -#include <errno.h> -#include <fcntl.h> #include <inttypes.h> -#include <sys/types.h> #include <sys/wait.h> -#include <unistd.h> #include <string> diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h index d2193f41b80a..dd5c0cfa04c1 100644 --- a/cmds/statsd/src/external/PullDataReceiver.h +++ b/cmds/statsd/src/external/PullDataReceiver.h @@ -15,8 +15,6 @@ */ #pragma once -#include <utils/String16.h> -#include <unordered_map> #include <utils/RefBase.h> #include "StatsPuller.h" #include "logd/LogEvent.h" diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h index ac88524a72ee..fe6af19e3901 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.h +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -17,7 +17,6 @@ #pragma once #include <android/os/IPullAtomCallback.h> -#include <utils/String16.h> #include "StatsPuller.h" diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index fef213dad60e..15d7e33d63fd 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -37,12 +37,8 @@ #include "TrainInfoPuller.h" #include "statslog.h" -using std::make_shared; -using std::map; using std::shared_ptr; -using std::string; using std::vector; -using std::list; namespace android { namespace os { @@ -84,7 +80,7 @@ bool StatsPullerManager::PullLocked(int tagId, vector<shared_ptr<LogEvent>>* dat } return ret; } else { - VLOG("Unknown tagId %d", tagId); + ALOGW("StatsPullerManager: Unknown tagId %d", tagId); return false; // Return early since we don't know what to pull. } } diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index f5d6057c2aec..aef16dcf2147 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -23,8 +23,6 @@ #include <utils/threads.h> #include <list> -#include <string> -#include <unordered_map> #include <vector> #include "PullDataReceiver.h" diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index a836bd14c012..3054b6d2204b 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -36,7 +36,6 @@ using android::util::FIELD_TYPE_MESSAGE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; using std::lock_guard; -using std::map; using std::shared_ptr; using std::string; using std::vector; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 583dae2f1b21..3db26765326d 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -20,11 +20,9 @@ #include <android/frameworks/stats/1.0/types.h> #include <android/util/ProtoOutputStream.h> -#include <log/log_read.h> #include <private/android_logger.h> #include <stats_event_list.h> #include <stats_event.h> -#include <utils/Errors.h> #include <string> #include <vector> diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h index b4fd63f119e6..9dda3d24c571 100644 --- a/cmds/statsd/src/logd/LogEventQueue.h +++ b/cmds/statsd/src/logd/LogEventQueue.h @@ -19,10 +19,8 @@ #include "LogEvent.h" #include <condition_variable> -#include <memory> #include <mutex> #include <queue> -#include <thread> namespace android { namespace os { diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 7d446a9a1ed6..58bfeb337da4 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -20,16 +20,11 @@ #include "StatsService.h" #include "socket/StatsSocketListener.h" -#include <binder/IInterface.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/ProcessState.h> -#include <binder/Status.h> #include <hidl/HidlTransportSupport.h> #include <utils/Looper.h> -#include <utils/StrongPointer.h> - -#include <memory> #include <stdio.h> #include <sys/stat.h> diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp index 15c067ee936d..b94a9572113e 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp @@ -24,8 +24,6 @@ namespace os { namespace statsd { using std::set; -using std::string; -using std::unique_ptr; using std::unordered_map; using std::vector; diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h index 2a3f08da7b96..55bc46059fc1 100644 --- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h @@ -16,9 +16,6 @@ #ifndef COMBINATION_LOG_MATCHING_TRACKER_H #define COMBINATION_LOG_MATCHING_TRACKER_H -#include <log/log_read.h> -#include <log/logprint.h> -#include <set> #include <unordered_map> #include <vector> #include "LogMatchingTracker.h" diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.cpp b/cmds/statsd/src/matchers/EventMatcherWizard.cpp index 8418e9833509..025c9a87b16b 100644 --- a/cmds/statsd/src/matchers/EventMatcherWizard.cpp +++ b/cmds/statsd/src/matchers/EventMatcherWizard.cpp @@ -14,14 +14,11 @@ * limitations under the License. */ #include "EventMatcherWizard.h" -#include <unordered_set> namespace android { namespace os { namespace statsd { -using std::map; -using std::string; using std::vector; MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcher_index) { diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp index 31b3db524e80..082daf5a1916 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp @@ -23,8 +23,6 @@ namespace android { namespace os { namespace statsd { -using std::string; -using std::unique_ptr; using std::unordered_map; using std::vector; diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h index 28b339caa466..a0f6a888bd44 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h +++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h @@ -17,9 +17,6 @@ #ifndef SIMPLE_LOG_MATCHING_TRACKER_H #define SIMPLE_LOG_MATCHING_TRACKER_H -#include <log/log_read.h> -#include <log/logprint.h> -#include <set> #include <unordered_map> #include <vector> #include "LogMatchingTracker.h" diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 476fae37899d..1f8bbd7f528c 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -23,7 +23,6 @@ using std::set; using std::string; -using std::unordered_map; using std::vector; namespace android { diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h index 15b4a9799a93..1ab3e87b5fed 100644 --- a/cmds/statsd/src/matchers/matcher_util.h +++ b/cmds/statsd/src/matchers/matcher_util.h @@ -18,11 +18,6 @@ #include "logd/LogEvent.h" -#include <log/log_read.h> -#include <log/logprint.h> -#include <set> -#include <string> -#include <unordered_map> #include <vector> #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "packages/UidMap.h" diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index 4ab6fd48f1db..83983e80d479 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -21,8 +21,6 @@ #include "GaugeMetricProducer.h" #include "../stats_log_util.h" -#include <cutils/log.h> - using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_BOOL; using android::util::FIELD_TYPE_FLOAT; diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index 5c29cb3c27fe..be754e29b5bd 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -33,7 +33,6 @@ namespace android { namespace os { namespace statsd { -using std::map; // for ActiveMetric const int FIELD_ID_ACTIVE_METRIC_ID = 1; diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 99f0c64bd47c..d721514ed1f0 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -18,7 +18,6 @@ #define METRIC_PRODUCER_H #include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> -#include <log/logprint.h> #include <utils/RefBase.h> #include <unordered_map> diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 088f607ecfce..536700f3bfe7 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -18,9 +18,7 @@ #include "MetricsManager.h" -#include <log/logprint.h> #include <private/android_filesystem_config.h> -#include <utils/SystemClock.h> #include "CountMetricProducer.h" #include "atoms_info.h" @@ -42,10 +40,8 @@ using android::util::FIELD_TYPE_MESSAGE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; -using std::make_unique; using std::set; using std::string; -using std::unordered_map; using std::vector; namespace android { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index d2db6e9c9ead..2a5b5302b619 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -21,7 +21,6 @@ #include "../guardrail/StatsdStats.h" #include "../stats_log_util.h" -#include <cutils/log.h> #include <limits.h> #include <stdlib.h> @@ -33,12 +32,8 @@ using android::util::FIELD_TYPE_INT64; using android::util::FIELD_TYPE_MESSAGE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; -using std::list; -using std::make_pair; -using std::make_shared; using std::map; using std::shared_ptr; -using std::unique_ptr; using std::unordered_map; namespace android { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 19fb6942928f..50317b341843 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -17,8 +17,6 @@ #pragma once #include <gtest/gtest_prod.h> -#include <utils/threads.h> -#include <list> #include "anomaly/AnomalyTracker.h" #include "condition/ConditionTimer.h" #include "condition/ConditionTracker.h" diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h index c3aad668aa78..f44e3275b83d 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h @@ -19,7 +19,6 @@ #include "DurationTracker.h" -#include <set> namespace android { namespace os { namespace statsd { diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 17f62b056426..40a313a14eab 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -40,7 +40,6 @@ #include "stats_util.h" using std::set; -using std::string; using std::unordered_map; using std::vector; diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 95b2ab81fa53..5ebb232694a4 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -16,7 +16,6 @@ #pragma once -#include <memory> #include <set> #include <unordered_map> #include <vector> diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h index fcdbe69dbbd1..6c50a8c41770 100644 --- a/cmds/statsd/src/packages/PackageInfoListener.h +++ b/cmds/statsd/src/packages/PackageInfoListener.h @@ -17,7 +17,6 @@ #ifndef STATSD_PACKAGE_INFO_LISTENER_H #define STATSD_PACKAGE_INFO_LISTENER_H -#include <utils/RefBase.h> #include <string> namespace android { diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index 7e63bbff2d0a..ab0e86e24b02 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -21,10 +21,6 @@ #include "guardrail/StatsdStats.h" #include "packages/UidMap.h" -#include <android/os/IStatsCompanionService.h> -#include <binder/IServiceManager.h> -#include <utils/Errors.h> - #include <inttypes.h> using namespace android; diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index 2d3f6ee9c2e8..bfac6e3431b0 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -21,10 +21,8 @@ #include "packages/PackageInfoListener.h" #include "stats_util.h" -#include <binder/IResultReceiver.h> #include <binder/IShellCallback.h> #include <gtest/gtest_prod.h> -#include <log/logprint.h> #include <stdio.h> #include <utils/RefBase.h> #include <list> diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index f7e32d4aed26..d6a04336bc46 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -18,7 +18,6 @@ #include "ShellSubscriber.h" -#include <android-base/file.h> #include "matchers/matcher_util.h" #include "stats_log_util.h" diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h index 8e54a8b00091..86d85901083a 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.h +++ b/cmds/statsd/src/shell/ShellSubscriber.h @@ -22,7 +22,6 @@ #include <binder/IResultReceiver.h> #include <condition_variable> #include <mutex> -#include <string> #include <thread> #include "external/StatsPullerManager.h" #include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h" diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp index cdb4d3a10f27..8f0f480cb862 100755 --- a/cmds/statsd/src/socket/StatsSocketListener.cpp +++ b/cmds/statsd/src/socket/StatsSocketListener.cpp @@ -27,9 +27,6 @@ #include <unistd.h> #include <cutils/sockets.h> -#include <private/android_filesystem_config.h> -#include <private/android_logger.h> -#include <unordered_map> #include "StatsSocketListener.h" #include "guardrail/StatsdStats.h" diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h index 8bc24612be90..8b3a4218238c 100644 --- a/cmds/statsd/src/state/StateManager.h +++ b/cmds/statsd/src/state/StateManager.h @@ -15,7 +15,6 @@ */ #pragma once -#include <gtest/gtest_prod.h> #include <inttypes.h> #include <utils/RefBase.h> diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp index 3ad21e0c96ae..ab861275073c 100644 --- a/cmds/statsd/src/state/StateTracker.cpp +++ b/cmds/statsd/src/state/StateTracker.cpp @@ -26,7 +26,9 @@ namespace os { namespace statsd { StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo) - : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) { + : mAtomId(atomId), + mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)), + mNested(stateAtomInfo.nested) { // create matcher for each primary field for (const auto& primaryField : stateAtomInfo.primaryFields) { if (primaryField == util::FIRST_UID_IN_CHAIN) { @@ -38,7 +40,13 @@ StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptio } } - // TODO(tsaichristine): b/142108433 set default state, reset state, and nesting + if (stateAtomInfo.defaultState != util::UNSET_VALUE) { + mDefaultState = stateAtomInfo.defaultState; + } + + if (stateAtomInfo.resetState != util::UNSET_VALUE) { + mResetState = stateAtomInfo.resetState; + } } void StateTracker::onLogEvent(const LogEvent& event) { @@ -60,7 +68,6 @@ void StateTracker::onLogEvent(const LogEvent& event) { // Parse event for state value. FieldValue stateValue; - int32_t state; if (!filterValues(mStateField, event.getValues(), &stateValue) || stateValue.mValue.getType() != INT) { ALOGE("StateTracker error extracting state from log event. Type: %d", @@ -68,11 +75,12 @@ void StateTracker::onLogEvent(const LogEvent& event) { handlePartialReset(eventTimeNs, primaryKey); return; } - state = stateValue.mValue.int_value; + int32_t state = stateValue.mValue.int_value; if (state == mResetState) { VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str()); handleReset(eventTimeNs); + return; } // Track and update state. @@ -113,15 +121,17 @@ bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValu return true; } } else if (queryKey.getValues().size() > mPrimaryFields.size()) { - ALOGE("StateTracker query key size > primary key size is illegal"); + ALOGE("StateTracker query key size %zu > primary key size %zu is illegal", + queryKey.getValues().size(), mPrimaryFields.size()); } else { - ALOGE("StateTracker query key size < primary key size is not supported"); + ALOGE("StateTracker query key size %zu < primary key size %zu is not supported", + queryKey.getValues().size(), mPrimaryFields.size()); } - // Set the state value to unknown if: + // Set the state value to default state if: // - query key size is incorrect // - query key is not found in state map - output->mValue = StateTracker::kStateUnknown; + output->mValue = mDefaultState; return false; } @@ -164,18 +174,52 @@ void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int *oldState = mDefaultState; } - // update state map - if (eventState == mDefaultState) { - // remove (key, state) pair if state returns to default state - VLOG("\t StateTracker changed to default state") - mStateMap.erase(primaryKey); - } else { - mStateMap[primaryKey].state = eventState; - mStateMap[primaryKey].count = 1; + // Update state map for non-nested counting case. + // Every state event triggers a state overwrite. + if (!mNested) { + if (eventState == mDefaultState) { + // remove (key, state) pair if state returns to default state + VLOG("\t StateTracker changed to default state") + mStateMap.erase(primaryKey); + } else { + mStateMap[primaryKey].state = eventState; + mStateMap[primaryKey].count = 1; + } + *newState = eventState; + return; } - *newState = eventState; - // TODO(tsaichristine): support atoms with nested counting + // Update state map for nested counting case. + // + // Nested counting is only allowed for binary state events such as ON/OFF or + // ACQUIRE/RELEASE. For example, WakelockStateChanged might have the state + // events: ON, ON, OFF. The state will still be ON until we see the same + // number of OFF events as ON events. + // + // In atoms.proto, a state atom with nested counting enabled + // must only have 2 states and one of the states must be the default state. + it = mStateMap.find(primaryKey); + if (it != mStateMap.end()) { + *newState = it->second.state; + if (eventState == it->second.state) { + it->second.count++; + } else if (eventState == mDefaultState) { + if ((--it->second.count) == 0) { + mStateMap.erase(primaryKey); + *newState = mDefaultState; + } + } else { + ALOGE("StateTracker Nest counting state has a third state instead of the binary state " + "limit."); + return; + } + } else { + if (eventState != mDefaultState) { + mStateMap[primaryKey].state = eventState; + mStateMap[primaryKey].count = 1; + } + *newState = eventState; + } } } // namespace statsd diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h index 70f16274c7f6..aeca2a53bfdc 100644 --- a/cmds/statsd/src/state/StateTracker.h +++ b/cmds/statsd/src/state/StateTracker.h @@ -74,6 +74,8 @@ private: int32_t mResetState = kStateUnknown; + const bool mNested; + // Maps primary key to state value info std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap; diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index 76c193679eef..8e0c62869932 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -17,12 +17,8 @@ #include "hash.h" #include "stats_log_util.h" -#include <logd/LogEvent.h> #include <private/android_filesystem_config.h> -#include <utils/Log.h> #include <set> -#include <stack> -#include <utils/Log.h> #include <utils/SystemClock.h> using android::util::AtomsInfo; diff --git a/cmds/statsd/src/statscompanion_util.h b/cmds/statsd/src/statscompanion_util.h index ff702f23f6d1..dc4f28361214 100644 --- a/cmds/statsd/src/statscompanion_util.h +++ b/cmds/statsd/src/statscompanion_util.h @@ -18,12 +18,6 @@ #include "StatsLogProcessor.h" -using namespace android; -using namespace android::base; -using namespace android::binder; -using namespace android::os; -using namespace std; - namespace android { namespace os { namespace statsd { diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 9b48a02c7f78..507297c6c401 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -23,10 +23,8 @@ #include "stats_log_util.h" #include <android-base/file.h> -#include <dirent.h> #include <private/android_filesystem_config.h> #include <fstream> -#include <iostream> namespace android { namespace os { diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index f1320c2f746d..d86e29131661 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -24,7 +24,6 @@ #include <android/os/IIncidentManager.h> #include <android/os/IncidentReportArgs.h> #include <android/util/ProtoOutputStream.h> -#include <binder/IBinder.h> #include <binder/IServiceManager.h> #include <vector> diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp index a37cad14fcbc..160b57e27c6c 100644 --- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp +++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp @@ -20,7 +20,6 @@ #include "SubscriberReporter.h" using std::lock_guard; -using std::unordered_map; namespace android { namespace os { diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp index c7ba9be3ca5a..5e60abaf7792 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp @@ -14,12 +14,12 @@ #include <gtest/gtest.h> +#include <vector> + #include "src/StatsLogProcessor.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" -#include <vector> - namespace android { namespace os { namespace statsd { @@ -29,12 +29,13 @@ namespace statsd { namespace { const int64_t metricId = 123456; +const int32_t ATOM_TAG = android::util::SUBSYSTEM_SLEEP_STATE; StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type, bool useCondition = true) { StatsdConfig config; config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. - auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE); + auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", ATOM_TAG); *config.add_atom_matcher() = atomMatcher; *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); @@ -51,7 +52,7 @@ StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type, gaugeMetric->set_sampling_type(sampling_type); gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true); *gaugeMetric->mutable_dimensions_in_what() = - CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */}); + CreateDimensions(ATOM_TAG, {1 /* subsystem name */}); gaugeMetric->set_bucket(FIVE_MINUTES); gaugeMetric->set_max_pull_delay_sec(INT_MAX); config.set_hash_strings_in_metric_report(false); @@ -69,8 +70,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), ATOM_TAG); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -144,7 +145,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { EXPECT_GT((int)gaugeMetrics.data_size(), 1); auto data = gaugeMetrics.data(0); - EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); EXPECT_EQ(1 /* subsystem name field */, data.dimensions_in_what().value_tuple().dimensions_value(0).field()); @@ -214,8 +215,8 @@ TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) { TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), ATOM_TAG); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -267,7 +268,7 @@ TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) { EXPECT_GT((int)gaugeMetrics.data_size(), 1); auto data = gaugeMetrics.data(0); - EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); EXPECT_EQ(1 /* subsystem name field */, data.dimensions_in_what().value_tuple().dimensions_value(0).field()); @@ -315,8 +316,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback, ATOM_TAG); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -371,7 +372,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { EXPECT_GT((int)gaugeMetrics.data_size(), 1); auto data = gaugeMetrics.data(0); - EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); EXPECT_EQ(1 /* subsystem name field */, data.dimensions_in_what().value_tuple().dimensions_value(0).field()); @@ -424,8 +425,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) { event_activation->set_ttl_seconds(ttlNs / 1000000000); ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), ATOM_TAG); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -493,7 +494,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) { EXPECT_GT((int)gaugeMetrics.data_size(), 0); auto data = gaugeMetrics.data(0); - EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); EXPECT_EQ(1 /* subsystem name field */, data.dimensions_in_what().value_tuple().dimensions_value(0).field()); @@ -542,8 +543,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) { TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), ATOM_TAG); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -586,7 +587,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) { EXPECT_GT((int)gaugeMetrics.data_size(), 0); auto data = gaugeMetrics.data(0); - EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field()); + EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field()); EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size()); EXPECT_EQ(1 /* subsystem name field */, data.dimensions_in_what().value_tuple().dimensions_value(0).field()); diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp index 16b51d99535b..9d58867f09db 100644 --- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp @@ -12,22 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <android/os/BnPullAtomCallback.h> +#include <android/os/IPullAtomResultReceiver.h> +#include <binder/IPCThreadState.h> #include <gtest/gtest.h> -#include <binder/IPCThreadState.h> +#include <vector> + #include "src/StatsLogProcessor.h" #include "src/StatsService.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" -#include <vector> - namespace android { namespace os { namespace statsd { #ifdef __ANDROID__ - +namespace { const string kApp1 = "app1.sharing.1"; const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs. const int kCallingUid = 0; // Randomly chosen @@ -109,6 +111,7 @@ StatsdConfig MakeGaugeMetricConfig(int64_t minTime) { gaugeMetric->set_min_bucket_size_nanos(minTime); return config; } +} // anonymous namespace TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) { StatsService service(nullptr, nullptr); @@ -202,6 +205,9 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { StatsService service(nullptr, nullptr); + service.mPullerManager->RegisterPullAtomCallback( + /*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {}, + new FakeSubsystemSleepCallback()); // Partial buckets don't occur when app is first installed. service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(0)); @@ -220,6 +226,9 @@ TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) { StatsService service(nullptr, nullptr); + service.mPullerManager->RegisterPullAtomCallback( + /*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {}, + new FakeSubsystemSleepCallback()); // Partial buckets don't occur when app is first installed. service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */)); diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp index e8d2ec514cad..a140af876474 100644 --- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp @@ -69,8 +69,9 @@ TEST(ValueMetricE2eTest, TestPulledEvents) { TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), + android::util::SUBSYSTEM_SLEEP_STATE); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -173,8 +174,9 @@ TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) { TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000; ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), + android::util::SUBSYSTEM_SLEEP_STATE); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); @@ -285,8 +287,9 @@ TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) { event_activation->set_ttl_seconds(ttlNs / 1000000000); ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor( - baseTimeNs, configAddedTimeNs, config, cfgKey); + auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey, + new FakeSubsystemSleepCallback(), + android::util::SUBSYSTEM_SLEEP_STATE); EXPECT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); processor->mPullerManager->ForceClearPullerCache(); diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp index 84aaa54bc5bf..b0acd5ad7452 100644 --- a/cmds/statsd/tests/state/StateTracker_test.cpp +++ b/cmds/statsd/tests/state/StateTracker_test.cpp @@ -127,6 +127,23 @@ std::shared_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::stri event->init(); return event; } + +std::shared_ptr<LogEvent> buildBleScanEvent(int uid, bool acquire, bool reset) { + std::vector<AttributionNodeInternal> chain; + chain.push_back(AttributionNodeInternal()); + AttributionNodeInternal& attr = chain.back(); + attr.set_uid(uid); + + std::shared_ptr<LogEvent> event = + std::make_shared<LogEvent>(android::util::BLE_SCAN_STATE_CHANGED, 1000); + event->write(chain); + event->write(reset ? 2 : acquire ? 1 : 0); // PARTIAL_WAKE_LOCK + event->write(0); // filtered + event->write(0); // first match + event->write(0); // opportunistic + event->init(); + return event; +} // END: build event functions. // START: get primary key functions @@ -277,6 +294,80 @@ TEST(StateTrackerTest, TestUnregisterListener) { } /** + * Test a binary state atom with nested counting. + * + * To go from an "ON" state to an "OFF" state with nested counting, we must see + * an equal number of "OFF" events as "ON" events. + * For example, ACQUIRE, ACQUIRE, RELEASE will still be in the ACQUIRE state. + * ACQUIRE, ACQUIRE, RELEASE, RELEASE will be in the RELEASE state. + */ +TEST(StateTrackerTest, TestStateChangeNested) { + sp<TestStateListener> listener = new TestStateListener(); + StateManager mgr; + mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener); + + std::shared_ptr<LogEvent> event1 = + buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/); + mgr.onLogEvent(*event1); + EXPECT_EQ(1, listener->updates.size()); + EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value); + EXPECT_EQ(1, listener->updates[0].mState); + listener->updates.clear(); + + std::shared_ptr<LogEvent> event2 = + buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/); + mgr.onLogEvent(*event2); + EXPECT_EQ(0, listener->updates.size()); + + std::shared_ptr<LogEvent> event3 = + buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/); + mgr.onLogEvent(*event3); + EXPECT_EQ(0, listener->updates.size()); + + std::shared_ptr<LogEvent> event4 = + buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/); + mgr.onLogEvent(*event4); + EXPECT_EQ(1, listener->updates.size()); + EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value); + EXPECT_EQ(0, listener->updates[0].mState); +} + +/** + * Test a state atom with a reset state. + * + * If the reset state value is seen, every state in the map is set to the default + * state and every listener is notified. + */ +TEST(StateTrackerTest, TestStateChangeReset) { + sp<TestStateListener> listener = new TestStateListener(); + StateManager mgr; + mgr.registerListener(android::util::BLE_SCAN_STATE_CHANGED, listener); + + std::shared_ptr<LogEvent> event1 = + buildBleScanEvent(1000 /* uid */, true /*acquire*/, false /*reset*/); + mgr.onLogEvent(*event1); + EXPECT_EQ(1, listener->updates.size()); + EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value); + EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState); + listener->updates.clear(); + + std::shared_ptr<LogEvent> event2 = + buildBleScanEvent(2000 /* uid */, true /*acquire*/, false /*reset*/); + mgr.onLogEvent(*event2); + EXPECT_EQ(1, listener->updates.size()); + EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value); + EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState); + listener->updates.clear(); + + std::shared_ptr<LogEvent> event3 = + buildBleScanEvent(2000 /* uid */, false /*acquire*/, true /*reset*/); + mgr.onLogEvent(*event3); + EXPECT_EQ(2, listener->updates.size()); + EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[0].mState); + EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[1].mState); +} + +/** * Test StateManager's onLogEvent and StateListener's onStateChanged correctly * updates listener for states without primary keys. */ @@ -334,7 +425,7 @@ TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) { // Log event. std::shared_ptr<LogEvent> event = - buildPartialWakelockEvent(1001 /* uid */, "tag1", false /* acquire */); + buildPartialWakelockEvent(1001 /* uid */, "tag1", true /* acquire */); mgr.onLogEvent(*event); EXPECT_EQ(1, mgr.getStateTrackersCount()); @@ -346,23 +437,25 @@ TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) { EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value); EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value); EXPECT_EQ("tag1", listener1->updates[0].mKey.getValues()[2].mValue.str_value); - EXPECT_EQ(WakelockStateChanged::RELEASE, listener1->updates[0].mState); + EXPECT_EQ(WakelockStateChanged::ACQUIRE, listener1->updates[0].mState); // Check StateTracker was updated by querying for state. HashableDimensionKey queryKey; getPartialWakelockKey(1001 /* uid */, "tag1", &queryKey); - EXPECT_EQ(WakelockStateChanged::RELEASE, + EXPECT_EQ(WakelockStateChanged::ACQUIRE, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey)); // No state stored for this query key. HashableDimensionKey queryKey2; getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2); - EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2)); + EXPECT_EQ(WakelockStateChanged::RELEASE, + getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2)); // Partial query fails. HashableDimensionKey queryKey3; getPartialWakelockKey(1001 /* uid */, &queryKey3); - EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3)); + EXPECT_EQ(WakelockStateChanged::RELEASE, + getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3)); } /** diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index e0aecceac4e3..6e1890ad63a9 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -580,9 +580,15 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( } sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs, - const StatsdConfig& config, const ConfigKey& key) { + const StatsdConfig& config, const ConfigKey& key, + const sp<IPullAtomCallback>& puller, + const int32_t atomTag) { sp<UidMap> uidMap = new UidMap(); sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + if (puller != nullptr) { + pullerManager->RegisterPullAtomCallback(/*uid=*/0, atomTag, NS_PER_SEC, NS_PER_SEC * 10, {}, + puller); + } sp<AlarmMonitor> anomalyAlarmMonitor = new AlarmMonitor(1, [](const sp<IStatsCompanionService>&, int64_t){}, [](const sp<IStatsCompanionService>&){}); @@ -942,6 +948,34 @@ void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) { } } +binder::Status FakeSubsystemSleepCallback::onPullAtom( + int atomTag, const sp<IPullAtomResultReceiver>& resultReceiver) { + // Convert stats_events into StatsEventParcels. + std::vector<android::util::StatsEventParcel> parcels; + for (int i = 1; i < 3; i++) { + stats_event* event = stats_event_obtain(); + stats_event_set_atom_id(event, atomTag); + std::string subsystemName = "subsystem_name_"; + subsystemName = subsystemName + std::to_string(i); + stats_event_write_string8(event, subsystemName.c_str()); + stats_event_write_string8(event, "subsystem_subname foo"); + stats_event_write_int64(event, /*count= */ i); + stats_event_write_int64(event, /*time_millis= */ i * 100); + stats_event_build(event); + size_t size; + uint8_t* buffer = stats_event_get_buffer(event, &size); + + android::util::StatsEventParcel p; + // vector.assign() creates a copy, but this is inevitable unless + // stats_event.h/c uses a vector as opposed to a buffer. + p.buffer.assign(buffer, buffer + size); + parcels.push_back(std::move(p)); + stats_event_release(event); + } + resultReceiver->pullFinished(atomTag, /*success=*/true, parcels); + return binder::Status::ok(); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 9bdfeebe561f..576a4916d60b 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -14,12 +14,16 @@ #pragma once +#include <android/os/BnPullAtomCallback.h> +#include <android/os/IPullAtomCallback.h> +#include <android/os/IPullAtomResultReceiver.h> #include <gtest/gtest.h> + #include "frameworks/base/cmds/statsd/src/stats_log.pb.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "src/StatsLogProcessor.h" -#include "src/logd/LogEvent.h" #include "src/hash.h" +#include "src/logd/LogEvent.h" #include "src/stats_log_util.h" #include "statslog.h" @@ -224,9 +228,10 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( AttributionNodeInternal CreateAttribution(const int& uid, const string& tag); // Create a statsd log event processor upon the start time in seconds, config and key. -sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, - const int64_t currentTimeNs, - const StatsdConfig& config, const ConfigKey& key); +sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs, + const StatsdConfig& config, const ConfigKey& key, + const sp<IPullAtomCallback>& puller = nullptr, + const int32_t atomTag = 0 /*for puller only*/); // Util function to sort the log events by timestamp. void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events); @@ -278,6 +283,12 @@ bool backfillDimensionPath(const DimensionsValue& path, const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues, DimensionsValue* dimension); +class FakeSubsystemSleepCallback : public BnPullAtomCallback { +public: + binder::Status onPullAtom(int atomTag, + const sp<IPullAtomResultReceiver>& resultReceiver) override; +}; + template <typename T> void backfillDimensionPath(const DimensionsValue& whatPath, const DimensionsValue& conditionPath, diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java index 19d158dedd06..28a21f767283 100644 --- a/core/java/android/app/AppCompatCallbacks.java +++ b/core/java/android/app/AppCompatCallbacks.java @@ -18,7 +18,6 @@ package android.app; import android.compat.Compatibility; import android.os.Process; -import android.util.StatsLog; import com.android.internal.compat.ChangeReporter; @@ -46,20 +45,20 @@ public final class AppCompatCallbacks extends Compatibility.Callbacks { mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length); Arrays.sort(mDisabledChanges); mChangeReporter = new ChangeReporter( - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS); + ChangeReporter.SOURCE_APP_PROCESS); } protected void reportChange(long changeId) { - reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + reportChange(changeId, ChangeReporter.STATE_LOGGED); } protected boolean isChangeEnabled(long changeId) { if (Arrays.binarySearch(mDisabledChanges, changeId) < 0) { // Not present in the disabled array - reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); + reportChange(changeId, ChangeReporter.STATE_ENABLED); return true; } - reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED); + reportChange(changeId, ChangeReporter.STATE_DISABLED); return false; } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 04d3e39b29fc..57cd8941a398 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -750,7 +750,7 @@ class ContextImpl extends Context { if (type != null) { dirs = Environment.buildPaths(dirs, type); } - return ensureExternalDirsExistOrFilter(dirs); + return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */); } } @@ -765,7 +765,7 @@ class ContextImpl extends Context { public File[] getObbDirs() { synchronized (mSync) { File[] dirs = Environment.buildExternalStorageAppObbDirs(getPackageName()); - return ensureExternalDirsExistOrFilter(dirs); + return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */); } } @@ -809,7 +809,10 @@ class ContextImpl extends Context { public File[] getExternalCacheDirs() { synchronized (mSync) { File[] dirs = Environment.buildExternalStorageAppCacheDirs(getPackageName()); - return ensureExternalDirsExistOrFilter(dirs); + // We don't try to create cache directories in-process, because they need special + // setup for accurate quota tracking. This ensures the cache dirs are always + // created through StorageManagerService. + return ensureExternalDirsExistOrFilter(dirs, false /* tryCreateInProcess */); } } @@ -817,7 +820,7 @@ class ContextImpl extends Context { public File[] getExternalMediaDirs() { synchronized (mSync) { File[] dirs = Environment.buildExternalStorageAppMediaDirs(getPackageName()); - return ensureExternalDirsExistOrFilter(dirs); + return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */); } } @@ -2804,24 +2807,24 @@ class ContextImpl extends Context { * Ensure that given directories exist, trying to create them if missing. If * unable to create, they are filtered by replacing with {@code null}. */ - private File[] ensureExternalDirsExistOrFilter(File[] dirs) { + private File[] ensureExternalDirsExistOrFilter(File[] dirs, boolean tryCreateInProcess) { final StorageManager sm = getSystemService(StorageManager.class); final File[] result = new File[dirs.length]; for (int i = 0; i < dirs.length; i++) { File dir = dirs[i]; if (!dir.exists()) { - if (!dir.mkdirs()) { - // recheck existence in case of cross-process race - if (!dir.exists()) { - // Failing to mkdir() may be okay, since we might not have - // enough permissions; ask vold to create on our behalf. - try { + try { + if (!tryCreateInProcess || !dir.mkdirs()) { + // recheck existence in case of cross-process race + if (!dir.exists()) { + // Failing to mkdir() may be okay, since we might not have + // enough permissions; ask vold to create on our behalf. sm.mkdirs(dir); - } catch (Exception e) { - Log.w(TAG, "Failed to ensure " + dir + ": " + e); - dir = null; } } + } catch (Exception e) { + Log.w(TAG, "Failed to ensure " + dir + ": " + e); + dir = null; } } result[i] = dir; diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 5a4622e0b245..4b24e098b3c6 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -15,8 +15,6 @@ */ package android.app; -import static android.annotation.SystemApi.Client.MODULE_APPS; - import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -362,7 +360,7 @@ public final class NotificationChannel implements Parcelable { * @param blockableSystem if {@code true}, allows users to block notifications on this channel. * @hide */ - @SystemApi(client = MODULE_APPS) + @SystemApi @TestApi public void setBlockableSystem(boolean blockableSystem) { mBlockableSystem = blockableSystem; diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java index 4c0e176c519e..bbc0bdfa6d7d 100644 --- a/core/java/android/app/admin/DevicePolicyEventLogger.java +++ b/core/java/android/app/admin/DevicePolicyEventLogger.java @@ -19,10 +19,9 @@ package android.app.admin; import android.annotation.Nullable; import android.content.ComponentName; import android.stats.devicepolicy.nano.StringList; -import android.util.StatsLog; import com.android.framework.protobuf.nano.MessageNano; -import com.android.internal.util.Preconditions; +import com.android.internal.util.FrameworkStatsLog; import java.util.Arrays; import java.util.Objects; @@ -197,8 +196,8 @@ public class DevicePolicyEventLogger { */ public void write() { byte[] bytes = stringArrayValueToBytes(mStringArrayValue); - StatsLog.write(StatsLog.DEVICE_POLICY_EVENT, mEventId, mAdminPackageName, mIntValue, - mBooleanValue, mTimePeriodMs, bytes); + FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_POLICY_EVENT, mEventId, mAdminPackageName, + mIntValue, mBooleanValue, mTimePeriodMs, bytes); } /** diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f71d78b40242..3676a9b2548f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -328,7 +328,7 @@ public class DevicePolicyManager { * modified by the user and the only way of resetting the device is via factory reset. * * <p>From version {@link android.os.Build.VERSION_CODES#Q}, the admin app can choose - * whether to set up a fully managed device or a work profile. For the admin app to support + * whether to set up a fully managed device or a managed profile. For the admin app to support * this, it must have an activity with intent filter {@link #ACTION_GET_PROVISIONING_MODE} and * another one with intent filter {@link #ACTION_ADMIN_POLICY_COMPLIANCE}. For example: * <pre> @@ -1781,12 +1781,13 @@ public class DevicePolicyManager { /** * Grants access to selection of KeyChain certificates on behalf of requesting apps. * Once granted the app will start receiving - * DelegatedAdminReceiver.onChoosePrivateKeyAlias. The caller (PO/DO) will + * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias}. The caller (PO/DO) will * no longer receive {@link DeviceAdminReceiver#onChoosePrivateKeyAlias}. * There can be at most one app that has this delegation. * If another app already had delegated certificate selection access, * it will lose the delegation when a new app is delegated. - * + * <p> The delegaetd app can also call {@link #grantKeyPairToApp} and + * {@link #revokeKeyPairFromApp} to directly grant KeyCain keys to other apps. * <p> Can be granted by Device Owner or Profile Owner. */ public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection"; @@ -4313,7 +4314,7 @@ public class DevicePolicyManager { * additionally call this method on the parent instance. * Calling this method on the parent {@link DevicePolicyManager} instance would wipe the * entire device, while calling it on the current profile instance would relinquish the device - * for personal use, removing the work profile and all policies set by the profile owner. + * for personal use, removing the managed profile and all policies set by the profile owner. * * @param flags Bit mask of additional options: currently supported flags are * {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA}, @@ -4339,7 +4340,7 @@ public class DevicePolicyManager { * additionally call this method on the parent instance. * Calling this method on the parent {@link DevicePolicyManager} instance would wipe the * entire device, while calling it on the current profile instance would relinquish the device - * for personal use, removing the work profile and all policies set by the profile owner. + * for personal use, removing the managed profile and all policies set by the profile owner. * * @param flags Bit mask of additional options: currently supported flags are * {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA} and @@ -11584,12 +11585,14 @@ public class DevicePolicyManager { * #setCrossProfilePackages(ComponentName, Set)}.</li> * <li>The default package names set by the OEM that are allowed to request user consent for * cross-profile communication without being explicitly enabled by the admin, via - * {@link com.android.internal.R.array#cross_profile_apps}</li> + * {@link com.android.internal.R.array#cross_profile_apps} and + * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li> * </ul> * * @return the combined set of whitelisted package names set via - * {@link #setCrossProfilePackages(ComponentName, Set)} and - * {@link com.android.internal.R.array#cross_profile_apps} + * {@link #setCrossProfilePackages(ComponentName, Set)}, + * {@link com.android.internal.R.array#cross_profile_apps}, + * and {@link com.android.internal.R.array#vendor_cross_profile_apps}. * * @hide */ @@ -11599,7 +11602,7 @@ public class DevicePolicyManager { permission.INTERACT_ACROSS_PROFILES }) public @NonNull Set<String> getAllCrossProfilePackages() { - throwIfParentInstance("getDefaultCrossProfilePackages"); + throwIfParentInstance("getAllCrossProfilePackages"); if (mService != null) { try { return new ArraySet<>(mService.getAllCrossProfilePackages()); @@ -11611,6 +11614,26 @@ public class DevicePolicyManager { } /** + * Returns the default package names set by the OEM that are allowed to request user consent for + * cross-profile communication without being explicitly enabled by the admin, via + * {@link com.android.internal.R.array#cross_profile_apps} and + * {@link com.android.internal.R.array#vendor_cross_profile_apps}. + * + * @hide + */ + public @NonNull Set<String> getDefaultCrossProfilePackages() { + throwIfParentInstance("getDefaultCrossProfilePackages"); + if (mService != null) { + try { + return new ArraySet<>(mService.getDefaultCrossProfilePackages()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return Collections.emptySet(); + } + + /** * Returns whether the device is being used as a managed kiosk. These requirements are as * follows: * <ul> diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 7fd0ae4a1a00..d2672eb3e2b2 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -457,6 +457,7 @@ interface IDevicePolicyManager { List<String> getCrossProfilePackages(in ComponentName admin); List<String> getAllCrossProfilePackages(); + List<String> getDefaultCrossProfilePackages(); boolean isManagedKiosk(); boolean isUnattendedManagedKiosk(); diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java index 50de73855511..da51ce2a6aff 100644 --- a/core/java/android/app/timedetector/ManualTimeSuggestion.java +++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java @@ -29,10 +29,18 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a manual (user provided) source. The value consists of the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime - * clock when that number was established. The elapsed realtime clock is considered accurate but - * volatile, so time signals must not be persisted across device resets. + * A time signal from a manual (user provided) source. + * + * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds + * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the + * elapsed realtime clock when the {@code utcTime.value} was established. + * Note that the elapsed realtime clock is considered accurate but it is volatile, so time + * suggestions cannot be persisted across device resets. + * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists and how it was entered. This information exists only to aid in + * debugging and therefore is used by {@link #toString()}, but it is not for use in detection + * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. * * @hide */ @@ -49,10 +57,8 @@ public final class ManualTimeSuggestion implements Parcelable { } }; - @NonNull - private final TimestampedValue<Long> mUtcTime; - @Nullable - private ArrayList<String> mDebugInfo; + @NonNull private final TimestampedValue<Long> mUtcTime; + @Nullable private ArrayList<String> mDebugInfo; public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { mUtcTime = Objects.requireNonNull(utcTime); diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java index 17e9c5a79fa5..89fd6f31e042 100644 --- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java +++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java @@ -29,10 +29,18 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a network time source like NTP. The value consists of the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime - * clock when that number was established. The elapsed realtime clock is considered accurate but - * volatile, so time signals must not be persisted across device resets. + * A time signal from a network time source like NTP. + * + * <p>{@code utcTime} contains the suggested time. The {@code utcTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the + * value of the elapsed realtime clock when the {@code utcTime.value} was established. + * Note that the elapsed realtime clock is considered accurate but it is volatile, so time + * suggestions cannot be persisted across device resets. + * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists and how it was determined. This information exists only to aid + * in debugging and therefore is used by {@link #toString()}, but it is not for use in detection + * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}. * * @hide */ @@ -49,10 +57,8 @@ public final class NetworkTimeSuggestion implements Parcelable { } }; - @NonNull - private final TimestampedValue<Long> mUtcTime; - @Nullable - private ArrayList<String> mDebugInfo; + @NonNull private final TimestampedValue<Long> mUtcTime; + @Nullable private ArrayList<String> mDebugInfo; public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) { mUtcTime = Objects.requireNonNull(utcTime); diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java index bd649f88f40a..16288e82d452 100644 --- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java +++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java @@ -32,12 +32,22 @@ import java.util.Objects; * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific * radio. * - * <p>The time value can be {@code null} to indicate that the telephony source has entered an - * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not - * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00 - * UTC and the time according to the elapsed realtime clock when that number was established. The - * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be - * persisted across device resets. + * <p>{@code slotIndex} identifies the suggestion source. This enables detection logic to identify + * suggestions from the same source when there are several in use. + * + * <p>{@code utcTime}. When not {@code null}, the {@code utcTime.value} is the number of + * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the + * value of the elapsed realtime clock when the {@code utcTime.value} was established. + * Note that the elapsed realtime clock is considered accurate but it is volatile, so time + * suggestions cannot be persisted across device resets. {@code utcTime} can be {@code null} to + * indicate that the telephony source has entered an "un-opinionated" state and any previous + * suggestion from the source is being withdrawn. + * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists, e.g. what triggered it to be made and what heuristic was used + * to determine the time or its absence. This information exists only to aid in debugging and + * therefore is used by {@link #toString()}, but it is not for use in detection logic and is not + * considered in {@link #hashCode()} or {@link #equals(Object)}. * * @hide */ @@ -57,19 +67,19 @@ public final class PhoneTimeSuggestion implements Parcelable { } }; - private final int mPhoneId; + private final int mSlotIndex; @Nullable private final TimestampedValue<Long> mUtcTime; @Nullable private ArrayList<String> mDebugInfo; private PhoneTimeSuggestion(Builder builder) { - mPhoneId = builder.mPhoneId; + mSlotIndex = builder.mSlotIndex; mUtcTime = builder.mUtcTime; mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null; } private static PhoneTimeSuggestion createFromParcel(Parcel in) { - int phoneId = in.readInt(); - PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(phoneId) + int slotIndex = in.readInt(); + PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(slotIndex) .setUtcTime(in.readParcelable(null /* classLoader */)) .build(); @SuppressWarnings("unchecked") @@ -87,22 +97,24 @@ public final class PhoneTimeSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mPhoneId); + dest.writeInt(mSlotIndex); dest.writeParcelable(mUtcTime, 0); dest.writeList(mDebugInfo); } /** - * Returns an identifier for the source of this suggestion. When a device has several "phones", - * i.e. sim slots or equivalent, it is used to identify which one. + * Returns an identifier for the source of this suggestion. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}. */ - public int getPhoneId() { - return mPhoneId; + public int getSlotIndex() { + return mSlotIndex; } /** - * Returns the suggestion. {@code null} means that the caller is no longer sure what time it - * is. + * Returns the suggested time or {@code null} if there isn't one. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}. */ @Nullable public TimestampedValue<Long> getUtcTime() { @@ -110,8 +122,9 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** - * Returns debug metadata for the suggestion. The information is present in {@link #toString()} - * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + * Returns debug metadata for the suggestion. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}. */ @NonNull public List<String> getDebugInfo() { @@ -120,9 +133,9 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** - * Associates information with the instance that can be useful for debugging / logging. The - * information is present in {@link #toString()} but is not considered for - * {@link #equals(Object)} and {@link #hashCode()}. + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}. */ public void addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { @@ -132,9 +145,9 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** - * Associates information with the instance that can be useful for debugging / logging. The - * information is present in {@link #toString()} but is not considered for - * {@link #equals(Object)} and {@link #hashCode()}. + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}. */ public void addDebugInfo(@NonNull List<String> debugInfo) { if (mDebugInfo == null) { @@ -152,19 +165,19 @@ public final class PhoneTimeSuggestion implements Parcelable { return false; } PhoneTimeSuggestion that = (PhoneTimeSuggestion) o; - return mPhoneId == that.mPhoneId + return mSlotIndex == that.mSlotIndex && Objects.equals(mUtcTime, that.mUtcTime); } @Override public int hashCode() { - return Objects.hash(mPhoneId, mUtcTime); + return Objects.hash(mSlotIndex, mUtcTime); } @Override public String toString() { return "PhoneTimeSuggestion{" - + "mPhoneId='" + mPhoneId + '\'' + + "mSlotIndex='" + mSlotIndex + '\'' + ", mUtcTime=" + mUtcTime + ", mDebugInfo=" + mDebugInfo + '}'; @@ -177,16 +190,24 @@ public final class PhoneTimeSuggestion implements Parcelable { */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { - private final int mPhoneId; + private final int mSlotIndex; @Nullable private TimestampedValue<Long> mUtcTime; @Nullable private List<String> mDebugInfo; - /** Creates a builder with the specified {@code phoneId}. */ - public Builder(int phoneId) { - mPhoneId = phoneId; + /** + * Creates a builder with the specified {@code slotIndex}. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}. + */ + public Builder(int slotIndex) { + mSlotIndex = slotIndex; } - /** Returns the builder for call chaining. */ + /** + * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}. + */ @NonNull public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { if (utcTime != null) { @@ -198,7 +219,11 @@ public final class PhoneTimeSuggestion implements Parcelable { return this; } - /** Returns the builder for call chaining. */ + /** + * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}. + */ @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java index a6b953b42f8f..3a9adc72aab1 100644 --- a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java +++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java @@ -28,10 +28,14 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a manual (user provided) source. The value consists of the number of - * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime - * clock when that number was established. The elapsed realtime clock is considered accurate but - * volatile, so time signals must not be persisted across device resets. + * A time signal from a manual (user provided) source. + * + * <p>{@code zoneId} contains the suggested time zone ID, e.g. "America/Los_Angeles". + * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists and how it was entered. This information exists only to aid in + * debugging and therefore is used by {@link #toString()}, but it is not for use in detection logic + * and is not considered in {@link #hashCode()} or {@link #equals(Object)}. * * @hide */ @@ -48,10 +52,8 @@ public final class ManualTimeZoneSuggestion implements Parcelable { } }; - @NonNull - private final String mZoneId; - @Nullable - private ArrayList<String> mDebugInfo; + @NonNull private final String mZoneId; + @Nullable private ArrayList<String> mDebugInfo; public ManualTimeZoneSuggestion(@NonNull String zoneId) { mZoneId = Objects.requireNonNull(zoneId); diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java index d71ffcb9f772..0544ccd3f4c5 100644 --- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java +++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java @@ -34,10 +34,14 @@ import java.util.Objects; * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information * associated with a specific radio. * - * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an - * "un-opinionated" state and any previous suggestions from that source are being withdrawn. - * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be - * used to judge quality / certainty of the suggestion. + * <p>{@code slotIndex} identifies the suggestion source. This enables detection logic to identify + * suggestions from the same source when there are several in use. + * + * <p>{@code zoneId}. When not {@code null}, {@code zoneId} contains the suggested time zone ID, + * e.g. "America/Los_Angeles". Suggestion metadata like {@code matchType} and {@code quality} can be + * used to judge quality / certainty of the suggestion. {@code zoneId} can be {@code null} to + * indicate that the telephony source has entered an "un-opinionated" state and any previous + * suggestion from the same source is being withdrawn. * * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null}, * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}. @@ -45,6 +49,12 @@ import java.util.Objects; * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null}, * and one of the other {@code QUALITY_} values when it is not {@code null}. * + * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to + * record why the suggestion exists, e.g. what triggered it to be made and what heuristic was used + * to determine the time zone or its absence. This information exists only to aid in debugging and + * therefore is used by {@link #toString()}, but it is not for use in detection logic and is not + * considered in {@link #hashCode()} or {@link #equals(Object)}. + * * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @@ -66,12 +76,12 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { /** * Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with - * the same {@code phoneId}. + * the same {@code slotIndex}. */ @NonNull public static PhoneTimeZoneSuggestion createEmptySuggestion( - int phoneId, @NonNull String debugInfo) { - return new Builder(phoneId).addDebugInfo(debugInfo).build(); + int slotIndex, @NonNull String debugInfo) { + return new Builder(slotIndex).addDebugInfo(debugInfo).build(); } /** @hide */ @@ -131,41 +141,14 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { */ public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; - /** - * The ID of the phone this suggestion is associated with. For multiple-sim devices this - * helps to establish source so filtering / stickiness can be implemented. - */ - private final int mPhoneId; - - /** - * The suggestion. {@code null} means there is no current suggestion and any previous suggestion - * should be forgotten. - */ - @Nullable - private final String mZoneId; - - /** - * The type of "match" used to establish the time zone. - */ - @MatchType - private final int mMatchType; - - /** - * A measure of the quality of the time zone suggestion, i.e. how confident one could be in - * it. - */ - @Quality - private final int mQuality; - - /** - * Free-form debug information about how the suggestion was derived. Used for debug only, - * intentionally not used in equals(), etc. - */ - @Nullable - private List<String> mDebugInfo; + private final int mSlotIndex; + @Nullable private final String mZoneId; + @MatchType private final int mMatchType; + @Quality private final int mQuality; + @Nullable private List<String> mDebugInfo; private PhoneTimeZoneSuggestion(Builder builder) { - mPhoneId = builder.mPhoneId; + mSlotIndex = builder.mSlotIndex; mZoneId = builder.mZoneId; mMatchType = builder.mMatchType; mQuality = builder.mQuality; @@ -175,8 +158,8 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { @SuppressWarnings("unchecked") private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) { // Use the Builder so we get validation during build(). - int phoneId = in.readInt(); - PhoneTimeZoneSuggestion suggestion = new Builder(phoneId) + int slotIndex = in.readInt(); + PhoneTimeZoneSuggestion suggestion = new Builder(slotIndex) .setZoneId(in.readString()) .setMatchType(in.readInt()) .setQuality(in.readInt()) @@ -190,7 +173,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mPhoneId); + dest.writeInt(mSlotIndex); dest.writeString(mZoneId); dest.writeInt(mMatchType); dest.writeInt(mQuality); @@ -203,17 +186,19 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** - * Returns an identifier for the source of this suggestion. When a device has several "phones", - * i.e. sim slots or equivalent, it is used to identify which one. + * Returns an identifier for the source of this suggestion. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}. */ - public int getPhoneId() { - return mPhoneId; + public int getSlotIndex() { + return mSlotIndex; } /** * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that - * the caller is no longer sure what the current time zone is. See - * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules. + * the caller is no longer sure what the current time zone is. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}. */ @Nullable public String getZoneId() { @@ -222,8 +207,9 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { /** * Returns information about how the suggestion was determined which could be used to rank - * suggestions when several are available from different sources. See - * {@link PhoneTimeZoneSuggestion} for the associated rules. + * suggestions when several are available from different sources. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}. */ @MatchType public int getMatchType() { @@ -231,8 +217,9 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** - * Returns information about the likelihood of the suggested zone being correct. See - * {@link PhoneTimeZoneSuggestion} for the associated rules. + * Returns information about the likelihood of the suggested zone being correct. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}. */ @Quality public int getQuality() { @@ -240,8 +227,9 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** - * Returns debug metadata for the suggestion. The information is present in {@link #toString()} - * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + * Returns debug metadata for the suggestion. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}. */ @NonNull public List<String> getDebugInfo() { @@ -250,9 +238,9 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** - * Associates information with the instance that can be useful for debugging / logging. The - * information is present in {@link #toString()} but is not considered for - * {@link #equals(Object)} and {@link #hashCode()}. + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}. */ public void addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { @@ -262,9 +250,9 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** - * Associates information with the instance that can be useful for debugging / logging. The - * information is present in {@link #toString()} but is not considered for - * {@link #equals(Object)} and {@link #hashCode()}. + * Associates information with the instance that can be useful for debugging / logging. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}. */ public void addDebugInfo(@NonNull List<String> debugInfo) { if (mDebugInfo == null) { @@ -282,7 +270,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return false; } PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o; - return mPhoneId == that.mPhoneId + return mSlotIndex == that.mSlotIndex && mMatchType == that.mMatchType && mQuality == that.mQuality && Objects.equals(mZoneId, that.mZoneId); @@ -290,13 +278,13 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { @Override public int hashCode() { - return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality); + return Objects.hash(mSlotIndex, mZoneId, mMatchType, mQuality); } @Override public String toString() { return "PhoneTimeZoneSuggestion{" - + "mPhoneId=" + mPhoneId + + "mSlotIndex=" + mSlotIndex + ", mZoneId='" + mZoneId + '\'' + ", mMatchType=" + mMatchType + ", mQuality=" + mQuality @@ -311,18 +299,25 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { - private final int mPhoneId; + private final int mSlotIndex; @Nullable private String mZoneId; @MatchType private int mMatchType; @Quality private int mQuality; @Nullable private List<String> mDebugInfo; - public Builder(int phoneId) { - mPhoneId = phoneId; + /** + * Creates a builder with the specified {@code slotIndex}. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}. + */ + public Builder(int slotIndex) { + mSlotIndex = slotIndex; } /** * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}. */ @NonNull public Builder setZoneId(@Nullable String zoneId) { @@ -330,21 +325,33 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return this; } - /** Returns the builder for call chaining. */ + /** + * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}. + */ @NonNull public Builder setMatchType(@MatchType int matchType) { mMatchType = matchType; return this; } - /** Returns the builder for call chaining. */ + /** + * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}. + */ @NonNull public Builder setQuality(@Quality int quality) { mQuality = quality; return this; } - /** Returns the builder for call chaining. */ + /** + * Returns the builder for call chaining. + * + * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}. + */ @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index ec40b7e3508c..249e58244870 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5099,6 +5099,7 @@ public abstract class Context { * @hide */ @SystemApi + @TestApi public static final String APP_INTEGRITY_SERVICE = "app_integrity"; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index acffec98b2fc..6f8a99fce897 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4284,7 +4284,15 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE"; /** - * Used for looking up a Data Loader Service provider. + * Used by {@link services.core.java.com.android.server.pm.DataLoaderManagerService} + * for querying Data Loader Service providers. Data loader service providers register this + * intent filter in their manifests, so that they can be looked up and bound to by + * {@code DataLoaderManagerService}. + * + * Data loader service providers must be privileged apps. + * See {@link com.android.server.pm.PackageManagerShellCommandDataLoader} as an example of such + * data loader service provider. + * * @hide */ @SystemApi diff --git a/core/java/android/content/integrity/AppIntegrityManager.java b/core/java/android/content/integrity/AppIntegrityManager.java index e53ef66020f1..9f95d4d75f6f 100644 --- a/core/java/android/content/integrity/AppIntegrityManager.java +++ b/core/java/android/content/integrity/AppIntegrityManager.java @@ -19,6 +19,7 @@ package android.content.integrity; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.content.IntentSender; import android.content.pm.ParceledListSlice; @@ -33,6 +34,7 @@ import android.os.RemoteException; * * @hide */ +@TestApi @SystemApi @SystemService(Context.APP_INTEGRITY_SERVICE) public class AppIntegrityManager { @@ -100,4 +102,23 @@ public class AppIntegrityManager { throw e.rethrowAsRuntimeException(); } } + + /** + * Get current RuleSet on device. + * + * <p>Warning: this method is only used for tests. + * + * @hide + */ + @TestApi + @NonNull + public RuleSet getCurrentRuleSet() { + try { + ParceledListSlice<Rule> rules = mManager.getCurrentRules(); + String version = mManager.getCurrentRuleSetVersion(); + return new RuleSet.Builder().setVersion(version).addRules(rules.getList()).build(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index 76007e67798d..439d53661b8e 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -460,14 +460,14 @@ public abstract class AtomicFormula extends IntegrityFormula { } private static String hashValue(@Key int key, String value) { - // Hash the string value unless it is a PACKAGE_NAME or INSTALLER_NAME and the value is - // less than 33 characters. - if (value.length() <= 32) { + // Hash the string value if it is a PACKAGE_NAME or INSTALLER_NAME and the value is + // greater than 32 characters. + if (value.length() > 32) { if (key == PACKAGE_NAME || key == INSTALLER_NAME) { - return value; + return hash(value); } } - return hash(value); + return value; } private static String hash(String value) { diff --git a/core/java/android/content/integrity/IAppIntegrityManager.aidl b/core/java/android/content/integrity/IAppIntegrityManager.aidl index 6b73fd70bb99..4714ad7c7989 100644 --- a/core/java/android/content/integrity/IAppIntegrityManager.aidl +++ b/core/java/android/content/integrity/IAppIntegrityManager.aidl @@ -25,4 +25,5 @@ interface IAppIntegrityManager { void updateRuleSet(String version, in ParceledListSlice<Rule> rules, in IntentSender statusReceiver); String getCurrentRuleSetVersion(); String getCurrentRuleSetProvider(); + ParceledListSlice<Rule> getCurrentRules(); } diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java index 8505d32e3f02..a2d937e4df31 100644 --- a/core/java/android/content/integrity/IntegrityFormula.java +++ b/core/java/android/content/integrity/IntegrityFormula.java @@ -19,6 +19,7 @@ package android.content.integrity; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.integrity.AtomicFormula.BooleanAtomicFormula; import android.content.integrity.AtomicFormula.LongAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; @@ -37,6 +38,7 @@ import java.util.Arrays; * @hide */ @SystemApi +@TestApi @VisibleForTesting public abstract class IntegrityFormula { diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java index c421c4076d16..d29e6df5ec39 100644 --- a/core/java/android/content/integrity/Rule.java +++ b/core/java/android/content/integrity/Rule.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -37,6 +38,7 @@ import java.util.Objects; * * @hide */ +@TestApi @SystemApi @VisibleForTesting public final class Rule implements Parcelable { diff --git a/core/java/android/content/integrity/RuleSet.java b/core/java/android/content/integrity/RuleSet.java index b423b54a7d92..e121ff8bbcaa 100644 --- a/core/java/android/content/integrity/RuleSet.java +++ b/core/java/android/content/integrity/RuleSet.java @@ -18,6 +18,7 @@ package android.content.integrity; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import java.util.ArrayList; import java.util.Collections; @@ -29,6 +30,7 @@ import java.util.Objects; * * @hide */ +@TestApi @SystemApi public class RuleSet { private final String mVersion; diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index 33d17763fb24..dbe39547b0ca 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -44,6 +44,16 @@ public class OverlayManager { private final IOverlayManager mService; private final Context mContext; + /** + * Pre R a {@link java.lang.SecurityException} would only be thrown by setEnabled APIs (e + * .g. {@link #setEnabled(String, boolean, UserHandle)}) for a permission error. + * Since R this no longer holds true, and {@link java.lang.SecurityException} can be + * thrown for any number of reasons, none of which are exposed to the caller. + * + * <p>To maintain existing API behavior, if a legacy permission failure or actor enforcement + * failure occurs for an app not yet targeting R, coerce it into an {@link + * java.lang.IllegalStateException}, which existed in the source prior to R. + */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long THROW_SECURITY_EXCEPTIONS = 147340954; diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index b1b9454aeddd..2acbb97cb20a 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1467,6 +1467,8 @@ public class PackageInstaller { public DataLoaderParams dataLoaderParams; /** {@hide} */ public int rollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE; + /** {@hide} */ + public boolean forceQueryableOverride; /** * Construct parameters for a new package install session. @@ -1499,6 +1501,7 @@ public class PackageInstaller { installerPackageName = source.readString(); isMultiPackage = source.readBoolean(); isStaged = source.readBoolean(); + forceQueryableOverride = source.readBoolean(); requiredInstalledVersionCode = source.readLong(); DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable( DataLoaderParamsParcel.class.getClassLoader()); @@ -1528,6 +1531,7 @@ public class PackageInstaller { ret.installerPackageName = installerPackageName; ret.isMultiPackage = isMultiPackage; ret.isStaged = isStaged; + ret.forceQueryableOverride = forceQueryableOverride; ret.requiredInstalledVersionCode = requiredInstalledVersionCode; ret.dataLoaderParams = dataLoaderParams; ret.rollbackDataPolicy = rollbackDataPolicy; @@ -1904,6 +1908,14 @@ public class PackageInstaller { this.dataLoaderParams = dataLoaderParams; } + /** + * + * {@hide} + */ + public void setForceQueryable() { + this.forceQueryableOverride = true; + } + /** {@hide} */ public void dump(IndentingPrintWriter pw) { pw.printPair("mode", mode); @@ -1923,6 +1935,7 @@ public class PackageInstaller { pw.printPair("installerPackageName", installerPackageName); pw.printPair("isMultiPackage", isMultiPackage); pw.printPair("isStaged", isStaged); + pw.printPair("forceQueryable", forceQueryableOverride); pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode); pw.printPair("dataLoaderParams", dataLoaderParams); pw.printPair("rollbackDataPolicy", rollbackDataPolicy); @@ -1954,6 +1967,7 @@ public class PackageInstaller { dest.writeString(installerPackageName); dest.writeBoolean(isMultiPackage); dest.writeBoolean(isStaged); + dest.writeBoolean(forceQueryableOverride); dest.writeLong(requiredInstalledVersionCode); if (dataLoaderParams != null) { dest.writeParcelable(dataLoaderParams.getData(), flags); @@ -2078,6 +2092,8 @@ public class PackageInstaller { /** {@hide} */ public boolean isStaged; /** {@hide} */ + public boolean forceQueryable; + /** {@hide} */ public int parentSessionId = INVALID_ID; /** {@hide} */ public int[] childSessionIds = NO_SESSIONS; @@ -2135,6 +2151,7 @@ public class PackageInstaller { installFlags = source.readInt(); isMultiPackage = source.readBoolean(); isStaged = source.readBoolean(); + forceQueryable = source.readBoolean(); parentSessionId = source.readInt(); childSessionIds = source.createIntArray(); if (childSessionIds == null) { @@ -2476,6 +2493,14 @@ public class PackageInstaller { } /** + * Returns true if this session is marked as forceQueryable + * {@hide} + */ + public boolean isForceQueryable() { + return forceQueryable; + } + + /** * Returns {@code true} if this session is an active staged session. * * We consider a session active if it has been committed and it is either pending @@ -2636,6 +2661,7 @@ public class PackageInstaller { dest.writeInt(installFlags); dest.writeBoolean(isMultiPackage); dest.writeBoolean(isStaged); + dest.writeBoolean(forceQueryable); dest.writeInt(parentSessionId); dest.writeIntArray(childSessionIds); dest.writeBoolean(isStagedSessionApplied); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index dfe9fe64657d..b6b27b6e514a 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -954,6 +954,10 @@ public class PackageParser { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split"); } + // Apk directory is directly nested under the current directory + if (files.length == 1 && files[0].isDirectory()) { + return parseClusterPackageLite(files[0], flags); + } String packageName = null; int versionCode = 0; @@ -1327,12 +1331,9 @@ public class PackageParser { } } - pkg.setCodePath(packageDir.getCanonicalPath()); + pkg.setCodePath(lite.codePath); pkg.setUse32bitAbi(lite.use32bitAbi); return pkg; - } catch (IOException e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to get path: " + lite.baseCodePath, e); } finally { IoUtils.closeQuietly(assetLoader); } diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 90a332ccb430..5be9c910744d 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -97,6 +97,10 @@ public class ApkLiteParseUtils { throw new PackageParser.PackageParserException( PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split"); } + // Apk directory is directly nested under the current directory + if (files.length == 1 && files[0].isDirectory()) { + return parseClusterPackageLite(files[0], flags); + } String packageName = null; int versionCode = 0; diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java index 7506412f72cc..5c8c9a41a520 100644 --- a/core/java/android/content/pm/parsing/ApkParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkParseUtils.java @@ -205,11 +205,8 @@ public class ApkParseUtils { } } - return parsingPackage.setCodePath(packageDir.getCanonicalPath()) + return parsingPackage.setCodePath(lite.codePath) .setUse32BitAbi(lite.use32bitAbi); - } catch (IOException e) { - throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Failed to get path: " + lite.baseCodePath, e); } finally { IoUtils.closeQuietly(assetLoader); } diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index 4c114fdc5f10..125b676e14f7 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -18,6 +18,7 @@ package android.hardware.biometrics; import static android.Manifest.permission.USE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; +import static android.Manifest.permission.WRITE_DEVICE_CONFIG; import android.annotation.IntDef; import android.annotation.RequiresPermission; @@ -87,9 +88,15 @@ public class BiometricManager { /** * Empty set with no authenticators specified. + * + * <p>This constant is intended for use by {@link android.provider.DeviceConfig} to adjust + * the reported strength of a biometric sensor. It is not a valid parameter for any of the + * public {@link android.hardware.biometrics} APIs. + * * @hide */ @SystemApi + @RequiresPermission(WRITE_DEVICE_CONFIG) int EMPTY_SET = 0x0000; /** @@ -115,12 +122,16 @@ public class BiometricManager { /** * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the - * requirements for <strong>Convenience</strong>, as defined by the Android CDD. This - * is not a valid parameter to any of the {@link android.hardware.biometrics} APIs, since - * the CDD allows only {@link #BIOMETRIC_WEAK} and stronger authenticators to participate. + * requirements for <strong>Convenience</strong>, as defined by the Android CDD. + * + * <p>This constant is intended for use by {@link android.provider.DeviceConfig} to adjust + * the reported strength of a biometric sensor. It is not a valid parameter for any of the + * public {@link android.hardware.biometrics} APIs. + * * @hide */ @SystemApi + @RequiresPermission(WRITE_DEVICE_CONFIG) int BIOMETRIC_CONVENIENCE = 0x0FFF; /** diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index a385771484fd..7615b87c7102 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -91,7 +91,7 @@ public class CameraDeviceImpl extends CameraDevice private boolean mIdle = true; /** map request IDs to callback/request data */ - private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap = + private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>(); private int mRepeatingRequestId = REQUEST_ID_NONE; @@ -123,7 +123,7 @@ public class CameraDeviceImpl extends CameraDevice * An object tracking received frame numbers. * Updated when receiving callbacks from ICameraDeviceCallbacks. */ - private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker(); + private FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker(); private CameraCaptureSessionCore mCurrentSession; private int mNextSessionId = 0; @@ -892,6 +892,7 @@ public class CameraDeviceImpl extends CameraDevice HashSet<Integer> offlineStreamIds = new HashSet<Integer>(); SparseArray<OutputConfiguration> offlineConfiguredOutputs = new SparseArray<OutputConfiguration>(); + CameraOfflineSession ret; synchronized(mInterfaceLock) { if (mOfflineSessionImpl != null) { @@ -919,15 +920,20 @@ public class CameraDeviceImpl extends CameraDevice offlineStreamIds.add(streamId); } + stopRepeating(); mOfflineSessionImpl = new CameraOfflineSessionImpl(mCameraId, mCharacteristics, executor, listener, offlineConfiguredOutputs, - mConfiguredInput, mFrameNumberTracker, mCaptureCallbackMap, + mConfiguredInput, mConfiguredOutputs, mFrameNumberTracker, mCaptureCallbackMap, mRequestLastFrameNumbersList); + ret = mOfflineSessionImpl; mOfflineSwitchService = Executors.newSingleThreadExecutor(); mConfiguredOutputs.clear(); mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null); + mIdle = true; + mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>(); + mFrameNumberTracker = new FrameNumberTracker(); mCurrentSession.closeWithoutDraining(); mCurrentSession = null; @@ -949,11 +955,13 @@ public class CameraDeviceImpl extends CameraDevice mOfflineSessionImpl.setRemoteSession(remoteOfflineSession); } catch (CameraAccessException e) { mOfflineSessionImpl.notifyFailedSwitch(); + } finally { + mOfflineSessionImpl = null; } } }); - return mOfflineSessionImpl; + return ret; } public boolean supportsOfflineProcessing(Surface surface) { diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java index 1db377a61465..1d9d644c9306 100644 --- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java @@ -63,6 +63,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession private SimpleEntry<Integer, InputConfiguration> mOfflineInput = new SimpleEntry<>(REQUEST_ID_NONE, null); private SparseArray<OutputConfiguration> mOfflineOutputs = new SparseArray<>(); + private SparseArray<OutputConfiguration> mConfiguredOutputs = new SparseArray<>(); final Object mInterfaceLock = new Object(); // access from this class and Session only! @@ -96,6 +97,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession Executor offlineExecutor, CameraOfflineSessionCallback offlineCallback, SparseArray<OutputConfiguration> offlineOutputs, SimpleEntry<Integer, InputConfiguration> offlineInput, + SparseArray<OutputConfiguration> configuredOutputs, FrameNumberTracker frameNumberTracker, SparseArray<CaptureCallbackHolder> callbackMap, List<RequestLastFrameNumbersHolder> frameNumberList) { if ((cameraId == null) || (characteristics == null)) { @@ -117,6 +119,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession mOfflineRequestLastFrameNumbersList.addAll(frameNumberList); mFrameNumberTracker = frameNumberTracker; mCaptureCallbackMap = callbackMap; + mConfiguredOutputs = configuredOutputs; mOfflineOutputs = offlineOutputs; mOfflineInput = offlineInput; mOfflineExecutor = checkNotNull(offlineExecutor, "offline executor must not be null"); @@ -137,9 +140,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession @Override public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) { synchronized(mInterfaceLock) { - if (mRemoteSession == null) { - return; // Camera already closed - } switch (errorCode) { case CameraDeviceCallbacks.ERROR_CAMERA_REQUEST: @@ -177,6 +177,11 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession @Override public void onDeviceIdle() { synchronized(mInterfaceLock) { + if (mRemoteSession == null) { + Log.v(TAG, "Ignoring idle state notifications during offline switches"); + return; + } + Runnable idleDispatch = new Runnable() { @Override public void run() { @@ -203,8 +208,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession final CaptureCallbackHolder holder; synchronized(mInterfaceLock) { - if (mRemoteSession == null) return; // Camera already closed - // Get the callback for this frame ID, if there is one holder = CameraOfflineSessionImpl.this.mCaptureCallbackMap.get(requestId); @@ -269,8 +272,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession long frameNumber = resultExtras.getFrameNumber(); synchronized(mInterfaceLock) { - if (mRemoteSession == null) return; // Camera already closed - // TODO: Handle CameraCharacteristics access from CaptureResult correctly. result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE, mCharacteristics.get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE)); @@ -445,8 +446,12 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession if (errorCode == ERROR_CAMERA_BUFFER) { // Because 1 stream id could map to multiple surfaces, we need to specify both // streamId and surfaceId. - OutputConfiguration config = mOfflineOutputs.get( - resultExtras.getErrorStreamId()); + OutputConfiguration config; + if ((mRemoteSession == null) && !isClosed()) { + config = mConfiguredOutputs.get(resultExtras.getErrorStreamId()); + } else { + config = mOfflineOutputs.get(resultExtras.getErrorStreamId()); + } if (config == null) { Log.v(TAG, String.format( "Stream %d has been removed. Skipping buffer lost callback", @@ -538,11 +543,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession final Executor executor; final CameraCaptureSession.CaptureCallback callback; synchronized(mInterfaceLock) { - if (mRemoteSession == null) { - Log.w(TAG, "Camera closed while checking sequences"); - return; - } - int index = mCaptureCallbackMap.indexOfKey(requestId); holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null; @@ -575,7 +575,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession } // Call onCaptureSequenceCompleted - if ((sequenceCompleted) && (callback != null) && (executor == null)) { + if ((sequenceCompleted) && (callback != null) && (executor != null)) { Runnable resultDispatch = new Runnable() { @Override public void run() { @@ -592,7 +592,12 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession } finally { Binder.restoreCallingIdentity(ident); } + + if (mCaptureCallbackMap.size() == 0) { + getCallbacks().onDeviceIdle(); + } } + } } @@ -686,9 +691,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession Runnable closeDispatch = new Runnable() { @Override public void run() { - if (!isClosed()) { - mOfflineCallback.onClosed(CameraOfflineSessionImpl.this); - } + mOfflineCallback.onClosed(CameraOfflineSessionImpl.this); } }; diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index 3e995b624112..ece5c28884fa 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -194,6 +194,11 @@ public class AmbientDisplayConfiguration { return !TextUtils.isEmpty(ambientDisplayComponent()); } + /** {@hide} */ + public boolean dozeSuppressed(int user) { + return boolSettingDefaultOff(Settings.Secure.SUPPRESS_DOZE, user); + } + private boolean alwaysOnDisplayAvailable() { return mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnDisplayAvailable); } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index da9cc8a47a39..49e1d5e4f213 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -38,6 +38,7 @@ import android.app.Dialog; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; @@ -451,6 +452,9 @@ public class InputMethodService extends AbstractInputMethodService { @Nullable private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; + private boolean mAutomotiveHideNavBarForKeyboard; + private boolean mIsAutomotive; + /** * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} * The original app window token is passed from client app window. @@ -1230,6 +1234,11 @@ public class InputMethodService extends AbstractInputMethodService { super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mSettingsObserver = SettingsObserver.createAndRegister(this); + + mIsAutomotive = isAutomotive(); + mAutomotiveHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + // TODO(b/111364446) Need to address context lifecycle issue if need to re-create // for update resources & configuration correctly when show soft input // in non-default display. @@ -1239,12 +1248,16 @@ public class InputMethodService extends AbstractInputMethodService { WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars()); - // IME layout should always be inset by navigation bar, no matter it's current visibility. + // IME layout should always be inset by navigation bar, no matter its current visibility, + // unless automotive requests it, since automotive may hide the navigation bar. mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( new WindowInsets.Builder(insets).setInsets( navigationBars(), - insets.getInsetsIgnoringVisibility(navigationBars())) + mIsAutomotive && mAutomotiveHideNavBarForKeyboard + ? android.graphics.Insets.NONE + : insets.getInsetsIgnoringVisibility(navigationBars()) + ) .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set @@ -3284,6 +3297,11 @@ public class InputMethodService extends AbstractInputMethodService { : IME_VISIBLE) : 0); } + private boolean isAutomotive() { + return getApplicationContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + } + /** * Performs a dump of the InputMethodService's internal state. Override * to add your own information to the dump. diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 356b3448430a..0513feef801f 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -21,7 +21,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.app.Dialog; import android.content.Context; -import android.content.pm.PackageManager; import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; @@ -51,7 +50,6 @@ public class SoftInputWindow extends Dialog { final int mWindowType; final int mGravity; final boolean mTakesFocus; - final boolean mAutomotiveHideNavBarForKeyboard; private final Rect mBounds = new Rect(); @Retention(SOURCE) @@ -136,8 +134,6 @@ public class SoftInputWindow extends Dialog { mWindowType = windowType; mGravity = gravity; mTakesFocus = takesFocus; - mAutomotiveHideNavBarForKeyboard = context.getResources().getBoolean( - com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); initDockWindow(); } @@ -251,11 +247,6 @@ public class SoftInputWindow extends Dialog { windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; } - if (isAutomotive() && mAutomotiveHideNavBarForKeyboard) { - windowSetFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; - windowModFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; - } - getWindow().setFlags(windowSetFlags, windowModFlags); } @@ -347,10 +338,6 @@ public class SoftInputWindow extends Dialog { mWindowState = newState; } - private boolean isAutomotive() { - return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - } - private static String stateToString(@SoftInputWindowState int state) { switch (state) { case SoftInputWindowState.TOKEN_PENDING: diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java index b13e4b72aa22..140363c48227 100644 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -25,13 +25,16 @@ import android.os.Binder; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.RemoteException; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; /** @@ -57,6 +60,11 @@ import java.util.concurrent.Executor; * </ul> */ public class ConnectivityDiagnosticsManager { + /** @hide */ + @VisibleForTesting + public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder> + sCallbacks = new ConcurrentHashMap<>(); + private final Context mContext; private final IConnectivityManager mService; @@ -631,8 +639,9 @@ public class ConnectivityDiagnosticsManager { /** * Registers a ConnectivityDiagnosticsCallback with the System. * - * <p>Only apps that offer network connectivity to the user are allowed to register callbacks. - * This includes: + * <p>Only apps that offer network connectivity to the user should be registering callbacks. + * These are the only apps whose callbacks will be invoked by the system. Apps considered to + * meet these conditions include: * * <ul> * <li>Carrier apps with active subscriptions @@ -640,15 +649,14 @@ public class ConnectivityDiagnosticsManager { * <li>WiFi Suggesters * </ul> * - * <p>Callbacks will be limited to receiving notifications for networks over which apps provide - * connectivity. + * <p>Callbacks registered by apps not meeting the above criteria will not be invoked. * * <p>If a registering app loses its relevant permissions, any callbacks it registered will * silently stop receiving callbacks. * - * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If - * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException - * will be thrown. + * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is + * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with + * multiple NetworkRequests, an IllegalArgumentException will be thrown. * * @param request The NetworkRequest that will be used to match with Networks for which * callbacks will be fired @@ -657,15 +665,21 @@ public class ConnectivityDiagnosticsManager { * System * @throws IllegalArgumentException if the same callback instance is registered with multiple * NetworkRequests - * @throws SecurityException if the caller does not have appropriate permissions to register a - * callback */ public void registerConnectivityDiagnosticsCallback( @NonNull NetworkRequest request, @NonNull Executor e, @NonNull ConnectivityDiagnosticsCallback callback) { - // TODO(b/143187964): implement ConnectivityDiagnostics functionality - throw new UnsupportedOperationException("registerCallback() not supported yet"); + final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e); + if (sCallbacks.putIfAbsent(callback, binder) != null) { + throw new IllegalArgumentException("Callback is currently registered"); + } + + try { + mService.registerConnectivityDiagnosticsCallback(binder, request); + } catch (RemoteException exception) { + exception.rethrowFromSystemServer(); + } } /** @@ -678,7 +692,15 @@ public class ConnectivityDiagnosticsManager { */ public void unregisterConnectivityDiagnosticsCallback( @NonNull ConnectivityDiagnosticsCallback callback) { - // TODO(b/143187964): implement ConnectivityDiagnostics functionality - throw new UnsupportedOperationException("registerCallback() not supported yet"); + // unconditionally removing from sCallbacks prevents race conditions here, since remove() is + // atomic. + final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback); + if (binder == null) return; + + try { + mService.unregisterConnectivityDiagnosticsCallback(binder); + } catch (RemoteException exception) { + exception.rethrowFromSystemServer(); + } } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 0dc66b5052c5..6baa3832403f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -121,6 +121,14 @@ interface IConnectivityManager ParcelFileDescriptor establishVpn(in VpnConfig config); + boolean provisionVpnProfile(in VpnProfile profile, String packageName); + + void deleteVpnProfile(String packageName); + + void startVpnProfile(String packageName); + + void stopVpnProfile(String packageName); + VpnConfig getVpnConfig(int userId); @UnsupportedAppUsage diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index f95807a14f00..e60cc81bf9d2 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -20,8 +20,17 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Activity; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; +import android.os.RemoteException; + +import com.android.internal.net.VpnProfile; + +import java.io.IOException; +import java.security.GeneralSecurityException; /** * This class provides an interface for apps to manage platform VPN profiles @@ -41,6 +50,15 @@ public class VpnManager { @NonNull private final Context mContext; @NonNull private final IConnectivityManager mService; + private static Intent getIntentForConfirmation() { + final Intent intent = new Intent(); + final ComponentName componentName = ComponentName.unflattenFromString( + Resources.getSystem().getString( + com.android.internal.R.string.config_customVpnConfirmDialogComponent)); + intent.setComponent(componentName); + return intent; + } + /** * Create an instance of the VpnManger with the given context. * @@ -57,18 +75,49 @@ public class VpnManager { /** * Install a VpnProfile configuration keyed on the calling app's package name. * - * @param profile the PlatformVpnProfile provided by this package. Will override any previous - * PlatformVpnProfile stored for this package. - * @return an intent to request user consent if needed (null otherwise). + * <p>This method returns {@code null} if user consent has already been granted, or an {@link + * Intent} to a system activity. If an intent is returned, the application should launch the + * activity using {@link Activity#startActivityForResult} to request user consent. The activity + * may pop up a dialog to require user action, and the result will come back via its {@link + * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has + * consented, and the VPN profile can be started. + * + * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile + * stored for this package. + * @return an Intent requesting user consent to start the VPN, or null if consent is not + * required based on privileges or previous user consent. */ @Nullable public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) { - throw new UnsupportedOperationException("Not yet implemented"); + final VpnProfile internalProfile; + + try { + internalProfile = profile.toVpnProfile(); + } catch (GeneralSecurityException | IOException e) { + // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions + // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded + // string as required by the VpnProfile. + throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e); + } + + try { + // Profile can never be null; it either gets set, or an exception is thrown. + if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) { + return null; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return getIntentForConfirmation(); } /** Delete the VPN profile configuration that was provisioned by the calling app */ public void deleteProvisionedVpnProfile() { - throw new UnsupportedOperationException("Not yet implemented"); + try { + mService.deleteVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -78,11 +127,19 @@ public class VpnManager { * setup, or if user consent has not been granted */ public void startProvisionedVpnProfile() { - throw new UnsupportedOperationException("Not yet implemented"); + try { + mService.startVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** Tear down the VPN provided by the calling app (if any) */ public void stopProvisionedVpnProfile() { - throw new UnsupportedOperationException("Not yet implemented"); + try { + mService.stopVpnProfile(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } } diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 73e1adf134f2..223f92054f79 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.WorkerThread; import android.content.res.AssetFileDescriptor; import android.os.IUpdateEngine; import android.os.IUpdateEngineCallback; @@ -478,7 +479,7 @@ public class UpdateEngine { * </ul> */ @ErrorCode - public int errorCode() { + public int getErrorCode() { return mErrorCode; } @@ -492,14 +493,15 @@ public class UpdateEngine { * * @return The following values: * <ul> - * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li> - * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}. + * <li>zero if {@link #getErrorCode} returns {@link ErrorCodeConstants#SUCCESS}</li> + * <li>non-zero if {@link #getErrorCode} returns + * {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}. * Value is the estimated total space required on userdata partition.</li> * </ul> - * @throws IllegalStateException if {@link #errorCode} is not one of the above. + * @throws IllegalStateException if {@link #getErrorCode} is not one of the above. * */ - public long freeSpaceRequired() { + public long getFreeSpaceRequired() { if (mErrorCode == ErrorCodeConstants.SUCCESS) { return 0; } @@ -507,7 +509,7 @@ public class UpdateEngine { return mFreeSpaceRequired; } throw new IllegalStateException(String.format( - "freeSpaceRequired() is not available when error code is %d", mErrorCode)); + "getFreeSpaceRequired() is not available when error code is %d", mErrorCode)); } } @@ -531,8 +533,10 @@ public class UpdateEngine { * * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}. * @param headerKeyValuePairs See {@link #applyPayload}. - * @return See {@link AllocateSpaceResult}. + * @return See {@link AllocateSpaceResult#getErrorCode} and + * {@link AllocateSpaceResult#getFreeSpaceRequired}. */ + @WorkerThread @NonNull public AllocateSpaceResult allocateSpace( @NonNull String payloadMetadataFilename, @@ -583,6 +587,7 @@ public class UpdateEngine { * @throws ServiceSpecificException if other transient errors has occurred. * A reboot may or may not help resolving the issue. */ + @WorkerThread @ErrorCode public int cleanupAppliedPayload() { try { diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java index a0bfc1bf56b8..4a668791aeb9 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -31,17 +31,10 @@ package android.os.incremental; * @throws IllegalStateException the session is not an Incremental installation session. */ -import static dalvik.system.VMRuntime.getInstructionSet; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.DataLoaderParams; import android.content.pm.InstallationFile; -import android.os.IVold; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.util.ArraySet; import android.util.Slog; import java.io.File; @@ -58,26 +51,14 @@ import java.util.Random; public final class IncrementalFileStorages { private static final String TAG = "IncrementalFileStorages"; private @Nullable IncrementalStorage mDefaultStorage; - private @Nullable IncrementalStorage mApkStorage; - private @Nullable IncrementalStorage mObbStorage; private @Nullable String mDefaultDir; - private @Nullable String mObbDir; private @NonNull IncrementalManager mIncrementalManager; - private @Nullable ArraySet<String> mLibDirs; - private @NonNull String mPackageName; private @NonNull File mStageDir; /** - * Set up files and directories used in an installation session. - * Currently only used by Incremental Installation. - * For Incremental installation, the expected outcome of this function is: - * 0) All the files are in defaultStorage - * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the - * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage. - * 2) All lib files are in the sub directories as their names suggest, and in the same parent - * directory as the APK files. The files are linked from mApkStorage to defaultStorage. - * 3) OBB files are in another directory that is different from APK files and lib files, bound - * to mObbStorage. The files are linked from mObbStorage to defaultStorage. + * Set up files and directories used in an installation session. Only used by Incremental. + * All the files will be created in defaultStorage. + * TODO(b/133435829): code clean up * * @throws IllegalStateException the session is not an Incremental installation session. */ @@ -85,7 +66,6 @@ public final class IncrementalFileStorages { @NonNull File stageDir, @NonNull IncrementalManager incrementalManager, @NonNull DataLoaderParams dataLoaderParams) { - mPackageName = packageName; mStageDir = stageDir; mIncrementalManager = incrementalManager; if (dataLoaderParams.getComponentName().getPackageName().equals("local")) { @@ -114,83 +94,23 @@ public final class IncrementalFileStorages { } if (file.getFileType() == InstallationFile.FILE_TYPE_APK) { addApkFile(file); - } else if (file.getFileType() == InstallationFile.FILE_TYPE_OBB) { - addObbFile(file); - } else if (file.getFileType() == InstallationFile.FILE_TYPE_LIB) { - addLibFile(file); } else { throw new IOException("Unknown file type: " + file.getFileType()); } } private void addApkFile(@NonNull InstallationFile apk) throws IOException { - // Create a storage for APK files and lib files final String stageDirPath = mStageDir.getAbsolutePath(); - if (mApkStorage == null) { - mApkStorage = mIncrementalManager.createStorage(stageDirPath, mDefaultStorage, - IncrementalManager.CREATE_MODE_CREATE - | IncrementalManager.CREATE_MODE_TEMPORARY_BIND); - mApkStorage.bind(stageDirPath); - } - - if (!new File(mDefaultDir, apk.getName()).exists()) { - mDefaultStorage.makeFile(apk.getName(), apk.getSize(), null, + mDefaultStorage.bind(stageDirPath); + String apkName = apk.getName(); + File targetFile = Paths.get(stageDirPath, apkName).toFile(); + if (!targetFile.exists()) { + mDefaultStorage.makeFile(apkName, apk.getSize(), null, apk.getMetadata(), 0, null, null, null); } - // Assuming APK files are already named properly, e.g., "base.apk" - mDefaultStorage.makeLink(apk.getName(), mApkStorage, apk.getName()); - } - - private void addLibFile(@NonNull InstallationFile lib) throws IOException { - // TODO(b/136132412): remove this after we have incfs support for lib file mapping - if (mApkStorage == null) { - throw new IOException("Cannot add lib file without adding an apk file first"); - } - if (mLibDirs == null) { - mLibDirs = new ArraySet<>(); + if (targetFile.exists()) { + Slog.i(TAG, "!!! created: " + targetFile.getAbsolutePath()); } - String current = ""; - final Path libDirPath = Paths.get(lib.getName()).getParent(); - final int numDirComponents = libDirPath.getNameCount(); - for (int i = 0; i < numDirComponents; i++) { - String dirName = libDirPath.getName(i).toString(); - try { - dirName = getInstructionSet(dirName); - } catch (IllegalArgumentException ignored) { - } - current += dirName; - if (!mLibDirs.contains(current)) { - mDefaultStorage.makeDirectory(current); - mApkStorage.makeDirectory(current); - mLibDirs.add(current); - } - current += '/'; - } - String libFilePath = current + Paths.get(lib.getName()).getFileName(); - mDefaultStorage.makeFile(libFilePath, lib.getSize(), null, lib.getMetadata(), 0, null, null, - null); - mDefaultStorage.makeLink(libFilePath, mApkStorage, libFilePath); - } - - private void addObbFile(@NonNull InstallationFile obb) throws IOException { - if (mObbStorage == null) { - // Create a storage for OBB files - mObbDir = getTempDir(); - if (mObbDir == null) { - throw new IOException("Failed to create obb storage directory."); - } - mObbStorage = mIncrementalManager.createStorage( - mObbDir, mDefaultStorage, - IncrementalManager.CREATE_MODE_CREATE - | IncrementalManager.CREATE_MODE_TEMPORARY_BIND); - } - mDefaultStorage.makeFile(obb.getName(), obb.getSize(), null, obb.getMetadata(), 0, null, - null, null); - mDefaultStorage.makeLink(obb.getName(), mObbStorage, obb.getName()); - } - - private boolean hasObb() { - return (mObbStorage != null && mObbDir != null); } /** @@ -208,35 +128,6 @@ public final class IncrementalFileStorages { * Sets up obb storage directory and create bindings. */ public void finishSetUp() { - if (!hasObb()) { - return; - } - final String obbDir = "/storage/emulated/0/Android/obb"; - final String packageObbDir = String.format("%s/%s", obbDir, mPackageName); - final String packageObbDirRoot = - String.format("/mnt/runtime/%s/emulated/0/Android/obb/", mPackageName); - final String[] obbDirs = { - packageObbDirRoot + "read", - packageObbDirRoot + "write", - packageObbDirRoot + "full", - packageObbDirRoot + "default", - String.format("/data/media/0/Android/obb/%s", mPackageName), - packageObbDir, - }; - try { - Slog.i(TAG, "Creating obb directory '" + packageObbDir + "'"); - final IVold vold = IVold.Stub.asInterface(ServiceManager.getServiceOrThrow("vold")); - vold.setupAppDir(packageObbDir, obbDir, Process.ROOT_UID); - for (String d : obbDirs) { - mObbStorage.bindPermanent(d); - } - } catch (ServiceManager.ServiceNotFoundException ex) { - Slog.e(TAG, "vold service is not found."); - cleanUp(); - } catch (IOException | RemoteException ex) { - Slog.e(TAG, "Failed to create obb dir at: " + packageObbDir, ex); - cleanUp(); - } } /** @@ -247,26 +138,12 @@ public final class IncrementalFileStorages { if (mDefaultStorage != null && mDefaultDir != null) { try { mDefaultStorage.unBind(mDefaultDir); + mDefaultStorage.unBind(mStageDir.getAbsolutePath()); } catch (IOException ignored) { } mDefaultDir = null; mDefaultStorage = null; } - if (mApkStorage != null && mStageDir != null) { - try { - mApkStorage.unBind(mStageDir.getAbsolutePath()); - } catch (IOException ignored) { - } - mApkStorage = null; - } - if (mObbStorage != null && mObbDir != null) { - try { - mObbStorage.unBind(mObbDir); - } catch (IOException ignored) { - } - mObbDir = null; - mObbStorage = null; - } } private String getTempDir() { diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index 91dda0899a63..e5d1b43d5921 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -174,9 +174,12 @@ public final class IncrementalStorage { @Nullable byte[] metadata, int hashAlgorithm, @Nullable byte[] rootHash, @Nullable byte[] additionalData, @Nullable byte[] signature) throws IOException { try { + if (id == null && metadata == null) { + throw new IOException("File ID and metadata cannot both be null"); + } final IncrementalNewFileParams params = new IncrementalNewFileParams(); params.size = size; - params.metadata = metadata; + params.metadata = (metadata == null ? new byte[0] : metadata); params.fileId = idToBytes(id); if (hashAlgorithm != 0 || signature != null) { params.signature = new IncrementalSignature(); @@ -354,9 +357,10 @@ public final class IncrementalStorage { * @param id The id to convert * @return Byte array that contains the same ID. */ - public static byte[] idToBytes(UUID id) { + @NonNull + public static byte[] idToBytes(@Nullable UUID id) { if (id == null) { - return null; + return new byte[0]; } final ByteBuffer buf = ByteBuffer.wrap(new byte[UUID_BYTE_SIZE]); buf.putLong(id.getMostSignificantBits()); @@ -370,7 +374,8 @@ public final class IncrementalStorage { * @param bytes The id in byte array format, 16 bytes long * @return UUID constructed from the byte array. */ - public static UUID bytesToId(byte[] bytes) { + @NonNull + public static UUID bytesToId(byte[] bytes) throws IllegalArgumentException { if (bytes.length != UUID_BYTE_SIZE) { throw new IllegalArgumentException("Expected array of size " + UUID_BYTE_SIZE + ", got " + bytes.length); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 3ea64f13fe6b..bb1dafc50484 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -2309,6 +2309,121 @@ public class StorageManager { private static final String XATTR_CACHE_GROUP = "user.cache_group"; private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone"; + + // Matches AID_MEDIA_RW in android_filesystem_config.h + private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023; + + // Matches AID_MEDIA_IMAGE in android_filesystem_config.h + private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057; + + // Matches AID_MEDIA_AUDIO in android_filesystem_config.h + private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055; + + // Matches AID_MEDIA_VIDEO in android_filesystem_config.h + private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056; + + /** + * Constant for use with + * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file + * is not a media file. + * + * @hide + */ + @SystemApi + public static final int QUOTA_TYPE_MEDIA_NONE = 0; + + /** + * Constant for use with + * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file + * is an image file. + * + * @hide + */ + @SystemApi + public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; + + /** + * Constant for use with + * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file + * is an audio file. + * + * @hide + */ + @SystemApi + public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; + + /** + * Constant for use with + * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file + * is a video file. + * + * @hide + */ + @SystemApi + public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "QUOTA_TYPE_" }, value = { + QUOTA_TYPE_MEDIA_NONE, + QUOTA_TYPE_MEDIA_AUDIO, + QUOTA_TYPE_MEDIA_VIDEO, + QUOTA_TYPE_MEDIA_IMAGE, + }) + public @interface QuotaType {} + + private static native boolean setQuotaProjectId(String path, long projectId); + + /** + * Let StorageManager know that the quota type for a file on external storage should + * be updated. Android tracks quotas for various media types. Consequently, this should be + * called on first creation of a new file on external storage, and whenever the + * media type of the file is updated later. + * + * This API doesn't require any special permissions, though typical implementations + * will require being called from an SELinux domain that allows setting file attributes + * related to quota (eg the GID or project ID). + * + * The default platform user of this API is the MediaProvider process, which is + * responsible for managing all of external storage. + * + * @param path the path to the file for which we should update the quota type + * @param quotaType the quota type of the file; this is based on the + * {@code QuotaType} constants, eg + * {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO} + * + * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid + * quota type. + * @throws IOException if the quota type could not be updated. + * + * @hide + */ + @SystemApi + public void updateExternalStorageFileQuotaType(@NonNull File path, + @QuotaType int quotaType) throws IOException { + long projectId; + final String filePath = path.getCanonicalPath(); + switch (quotaType) { + case QUOTA_TYPE_MEDIA_NONE: + projectId = QUOTA_PROJECT_ID_MEDIA_NONE; + break; + case QUOTA_TYPE_MEDIA_AUDIO: + projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO; + break; + case QUOTA_TYPE_MEDIA_VIDEO: + projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO; + break; + case QUOTA_TYPE_MEDIA_IMAGE: + projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE; + break; + default: + throw new IllegalArgumentException("Invalid quota type: " + quotaType); + } + if (!setQuotaProjectId(filePath, projectId)) { + throw new IOException("Failed to update quota type for " + filePath); + } + } + /** {@hide} */ private static void setCacheBehavior(File path, String name, boolean enabled) throws IOException { diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 4812ea98b569..d945b65c8522 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -93,7 +93,10 @@ public final class PermissionManager { */ @TestApi @SystemApi - @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + @RequiresPermission(anyOf = { + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, + Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS + }) public @IntRange(from = 0) int getRuntimePermissionsVersion() { try { return mPackageManager.getRuntimePermissionsVersion(mContext.getUserId()); @@ -111,7 +114,10 @@ public final class PermissionManager { */ @TestApi @SystemApi - @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + @RequiresPermission(anyOf = { + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, + Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS + }) public void setRuntimePermissionsVersion(@IntRange(from = 0) int version) { try { mPackageManager.setRuntimePermissionsVersion(version, mContext.getUserId()); diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index e383a371eb41..146387e761d4 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -2381,11 +2381,7 @@ public final class ContactsContract { * This id is provided by its own data source, and can be used to backup metadata * to the server. * This should be unique within each set of account_name/account_type/data_set - * - * @deprecated This column is no longer supported as of Android version - * {@link android.os.Build.VERSION_CODES#R}. */ - @Deprecated public static final String BACKUP_ID = "backup_id"; /** @@ -2450,8 +2446,8 @@ public final class ContactsContract { * needs to be synchronized by the server. * <P>Type: INTEGER (boolean)</P> * - * @deprecated This column is no longer supported as of Android version - * {@link android.os.Build.VERSION_CODES#R}. + * @deprecated This column never actually worked since added. It will not supported as + * of Android version {@link android.os.Build.VERSION_CODES#R}. */ @Deprecated public static final String METADATA_DIRTY = "metadata_dirty"; @@ -4196,8 +4192,8 @@ public final class ContactsContract { * Hash id on the data fields, used for backup and restore. * * @hide - * @deprecated This column is no longer supported as of Android version - * {@link android.os.Build.VERSION_CODES#R}. + * @deprecated This column was never public since added. It will not be supported + * as of Android version {@link android.os.Build.VERSION_CODES#R}. */ @Deprecated public static final String HASH_ID = "hash_id"; @@ -9506,8 +9502,8 @@ public final class ContactsContract { /** * @hide - * @deprecated These columns are no longer supported as of Android version - * {@link android.os.Build.VERSION_CODES#R}. + * @deprecated These columns were never public since added. They will not be supported + * as of Android version {@link android.os.Build.VERSION_CODES#R}. */ @Deprecated @SystemApi @@ -9616,8 +9612,8 @@ public final class ContactsContract { * from server before it is merged into other CP2 tables. * * @hide - * @deprecated These columns are no longer supported as of Android version - * {@link android.os.Build.VERSION_CODES#R}. + * @deprecated These columns were never public since added. They will not be supported + * as of Android version {@link android.os.Build.VERSION_CODES#R}. */ @Deprecated @SystemApi diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 091d78e88c98..505d4ca4b399 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -383,6 +383,14 @@ public final class DeviceConfig { */ public static final String NAMESPACE_WIDGET = "widget"; + /** + * Namespace for connectivity thermal power manager features. + * + * @hide + */ + public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER = + "connectivity_thermal_power_manager"; + private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners = diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index bb1c8ed165c9..47f24615d60a 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -16,8 +16,6 @@ package android.provider; -import static android.annotation.SystemApi.Client.MODULE_APPS; - import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; import static com.android.internal.util.Preconditions.checkCollectionNotEmpty; @@ -955,7 +953,7 @@ public final class DocumentsContract { * * @hide */ - @SystemApi(client = MODULE_APPS) + @SystemApi @NonNull public static Uri buildDocumentUriAsUser( @NonNull String authority, @NonNull String documentId, @NonNull UserHandle user) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b62142c01c9b..30e4eee08e8d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14055,7 +14055,7 @@ public final class Settings { * means Common Criteria mode is enabled. * @hide */ - @SystemApi(client = SystemApi.Client.MODULE_APPS) + @SystemApi public static final String COMMON_CRITERIA_MODE = "common_criteria_mode"; } diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index 262d9896df87..886b433d4ade 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -322,6 +322,9 @@ public final class Dataset implements Parcelable { * platform needs to fill in the authentication arguments. * * @param authentication Intent to an activity with your authentication flow. + * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. * * @see android.app.PendingIntent @@ -349,6 +352,8 @@ public final class Dataset implements Parcelable { * * @param id id for this dataset or {@code null} to unset. * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. */ public @NonNull Builder setId(@Nullable String id) { @@ -378,6 +383,9 @@ public final class Dataset implements Parcelable { * @param value value to be autofilled. Pass {@code null} if you do not have the value * but the target view is a logical part of the dataset. For example, if * the dataset needs authentication and you have no access to the value. + * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) { @@ -403,8 +411,10 @@ public final class Dataset implements Parcelable { * but the target view is a logical part of the dataset. For example, if * the dataset needs authentication and you have no access to the value. * @param presentation the presentation used to visualize this field. - * @return this builder. * + * @throws IllegalStateException if {@link #build()} was already called. + * + * @return this builder. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value, @NonNull RemoteViews presentation) { @@ -439,7 +449,7 @@ public final class Dataset implements Parcelable { * * @return this builder. * @throws IllegalStateException if the builder was constructed without a - * {@link RemoteViews presentation}. + * {@link RemoteViews presentation} or {@link #build()} was already called. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value, @Nullable Pattern filter) { @@ -475,6 +485,8 @@ public final class Dataset implements Parcelable { * such as passwords). * @param presentation the presentation used to visualize this field. * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value, @@ -504,6 +516,8 @@ public final class Dataset implements Parcelable { * as inline suggestions. If the dataset supports inline suggestions, * this should not be null. * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value, @@ -544,6 +558,8 @@ public final class Dataset implements Parcelable { * as inline suggestions. If the dataset supports inline suggestions, this * should not be null. * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value, @@ -576,6 +592,8 @@ public final class Dataset implements Parcelable { * as inline suggestions. If the dataset supports inline suggestions, this * should not be null. * + * @throws IllegalStateException if {@link #build()} was already called. + * * @return this builder. * * @hide @@ -628,7 +646,8 @@ public final class Dataset implements Parcelable { * @throws IllegalStateException if no field was set (through * {@link #setValue(AutofillId, AutofillValue)} or * {@link #setValue(AutofillId, AutofillValue, RemoteViews)} or - * {@link #setValue(AutofillId, AutofillValue, RemoteViews, InlinePresentation)}). + * {@link #setValue(AutofillId, AutofillValue, RemoteViews, InlinePresentation)}), + * or if {@link #build()} was already called. * * @return The built dataset. */ diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 5a8521fead87..707426a22889 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -42,7 +42,6 @@ import android.os.RemoteException; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; -import android.util.StatsLog; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureEvent; @@ -55,6 +54,7 @@ import android.view.contentcapture.IContentCaptureDirectManager; import android.view.contentcapture.MainContentCaptureSession; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import java.io.FileDescriptor; @@ -594,7 +594,7 @@ public abstract class ContentCaptureService extends Service { + rightUid); long now = System.currentTimeMillis(); if (now - mLastCallerMismatchLog > mCallerMismatchTimeout) { - StatsLog.write(StatsLog.CONTENT_CAPTURE_CALLER_MISMATCH_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_CALLER_MISMATCH_REPORTED, getPackageManager().getNameForUid(rightUid), getPackageManager().getNameForUid(uid)); mLastCallerMismatchLog = now; diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 8635340397b4..cc922d398969 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -28,6 +28,8 @@ import android.os.IStatsd; import android.os.RemoteException; import android.os.ServiceManager; +import com.android.internal.util.FrameworkStatsLog; + /** * StatsLog provides an API for developers to send events to statsd. The events can be used to * define custom metrics inside statsd. @@ -60,7 +62,7 @@ public final class StatsLog extends StatsLogInternal { return false; } service.sendAppBreadcrumbAtom(label, - StatsLog.APP_BREADCRUMB_REPORTED__STATE__START); + FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__START); return true; } catch (RemoteException e) { sService = null; @@ -88,7 +90,8 @@ public final class StatsLog extends StatsLogInternal { } return false; } - service.sendAppBreadcrumbAtom(label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP); + service.sendAppBreadcrumbAtom( + label, FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP); return true; } catch (RemoteException e) { sService = null; @@ -117,7 +120,7 @@ public final class StatsLog extends StatsLogInternal { return false; } service.sendAppBreadcrumbAtom( - label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED); + label, FrameworkStatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED); return true; } catch (RemoteException e) { sService = null; diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index 19793b945ffd..f6c72c4eefbc 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -16,12 +16,12 @@ package android.view; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DOUBLE_TAP; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SCROLL; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DOUBLE_TAP; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SCROLL; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -29,7 +29,8 @@ import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.SystemClock; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; /** * Detects various gestures and events using the supplied {@link MotionEvent}s. @@ -887,8 +888,8 @@ public class GestureDetector { mHasRecordedClassification = true; return; } - StatsLog.write( - StatsLog.TOUCH_GESTURE_CLASSIFIED, + FrameworkStatsLog.write( + FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), classification, (int) (SystemClock.uptimeMillis() - mCurrentMotionEvent.getDownTime()), diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 1677357dedbe..91000a93b17c 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -318,5 +318,11 @@ interface IWindowSession { * an input channel where the client can receive input. */ void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window, - in IBinder hostInputToken, out InputChannel outInputChannel); + in IBinder hostInputToken, int flags, out InputChannel outInputChannel); + + /** + * Update the flags on an input channel associated with a particular surface. + */ + void updateInputChannel(in IBinder channelToken, int displayId, in SurfaceControl surface, + int flags); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bee05a9a57d0..fe9e36e53cd8 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -152,7 +152,8 @@ public final class SurfaceControl implements Parcelable { int L, int T, int R, int B); private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken, int width, int height); - private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs( + private static native SurfaceControl.DisplayInfo nativeGetDisplayInfo(IBinder displayToken); + private static native SurfaceControl.DisplayConfig[] nativeGetDisplayConfigs( IBinder displayToken); private static native DisplayedContentSamplingAttributes nativeGetDisplayedContentSamplingAttributes(IBinder displayToken); @@ -1278,140 +1279,45 @@ public final class SurfaceControl implements Parcelable { Integer.toHexString(System.identityHashCode(this)); } - /* - * set display parameters. - * needs to be inside open/closeTransaction block + /** + * Immutable information about physical display. + * + * @hide */ + public static final class DisplayInfo { + public float density; + public boolean secure; + + @Override + public String toString() { + return "DisplayInfo{density=" + density + ", secure=" + secure + "}"; + } + } /** - * Describes the properties of a physical display known to surface flinger. + * Configuration supported by physical display. + * * @hide */ - public static final class PhysicalDisplayInfo { - /** - * @hide - */ - @UnsupportedAppUsage + public static final class DisplayConfig { public int width; - - /** - * @hide - */ - @UnsupportedAppUsage public int height; - - /** - * @hide - */ - @UnsupportedAppUsage - public float refreshRate; - - /** - * @hide - */ - @UnsupportedAppUsage - public float density; - - /** - * @hide - */ - @UnsupportedAppUsage public float xDpi; - - /** - * @hide - */ - @UnsupportedAppUsage public float yDpi; - /** - * @hide - */ - @UnsupportedAppUsage - public boolean secure; - - /** - * @hide - */ - @UnsupportedAppUsage + public float refreshRate; public long appVsyncOffsetNanos; - - /** - * @hide - */ - @UnsupportedAppUsage public long presentationDeadlineNanos; - /** - * @hide - */ - @UnsupportedAppUsage - public PhysicalDisplayInfo() { - } - - /** - * @hide - */ - public PhysicalDisplayInfo(PhysicalDisplayInfo other) { - copyFrom(other); - } - - /** - * @hide - */ - @Override - public boolean equals(Object o) { - return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); - } - - /** - * @hide - */ - public boolean equals(PhysicalDisplayInfo other) { - return other != null - && width == other.width - && height == other.height - && refreshRate == other.refreshRate - && density == other.density - && xDpi == other.xDpi - && yDpi == other.yDpi - && secure == other.secure - && appVsyncOffsetNanos == other.appVsyncOffsetNanos - && presentationDeadlineNanos == other.presentationDeadlineNanos; - } - - /** - * @hide - */ - @Override - public int hashCode() { - return 0; // don't care - } - - /** - * @hide - */ - public void copyFrom(PhysicalDisplayInfo other) { - width = other.width; - height = other.height; - refreshRate = other.refreshRate; - density = other.density; - xDpi = other.xDpi; - yDpi = other.yDpi; - secure = other.secure; - appVsyncOffsetNanos = other.appVsyncOffsetNanos; - presentationDeadlineNanos = other.presentationDeadlineNanos; - } - - /** - * @hide - */ @Override public String toString() { - return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " - + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure - + ", appVsyncOffset " + appVsyncOffsetNanos - + ", bufferDeadline " + presentationDeadlineNanos + "}"; + return "DisplayConfig{width=" + width + + ", height=" + height + + ", xDpi=" + xDpi + + ", yDpi=" + yDpi + + ", refreshRate=" + refreshRate + + ", appVsyncOffsetNanos=" + appVsyncOffsetNanos + + ", presentationDeadlineNanos=" + presentationDeadlineNanos + "}"; } } @@ -1428,8 +1334,17 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - @UnsupportedAppUsage - public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) { + public static SurfaceControl.DisplayInfo getDisplayInfo(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + return nativeGetDisplayInfo(displayToken); + } + + /** + * @hide + */ + public static SurfaceControl.DisplayConfig[] getDisplayConfigs(IBinder displayToken) { if (displayToken == null) { throw new IllegalArgumentException("displayToken must not be null"); } @@ -1825,7 +1740,7 @@ public final class SurfaceControl implements Parcelable { } /** - * TODO(116025192): Remove this stopgap once framework is display-agnostic. + * TODO(b/116025192): Remove this stopgap once framework is display-agnostic. * * @hide */ diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 71cf051a4e08..bf848196454d 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -138,6 +138,7 @@ public class SurfaceControlViewHost { /** * @hide */ + @TestApi public void addView(@NonNull View view, WindowManager.LayoutParams attrs) { mViewRoot.setView(view, attrs, null); } @@ -161,6 +162,7 @@ public class SurfaceControlViewHost { /** * @hide */ + @TestApi public void relayout(WindowManager.LayoutParams attrs) { mViewRoot.setLayoutParams(attrs, false); mViewRoot.setReportNextDraw(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ee7f6fb11de6..70475860cb4d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17,13 +17,14 @@ package android.view; import static android.content.res.Resources.ID_NULL; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; -import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; +import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; + import static java.lang.Math.max; import android.animation.AnimatorInflater; @@ -102,7 +103,6 @@ import android.util.Property; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.StateSet; -import android.util.StatsLog; import android.util.SuperNotCalledException; import android.util.TypedValue; import android.view.AccessibilityIterators.CharacterTextSegmentIterator; @@ -142,6 +142,7 @@ import android.widget.FrameLayout; import android.widget.ScrollBarDrawable; import com.android.internal.R; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.view.TooltipPopup; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.widget.ScrollBarUtils; @@ -28059,7 +28060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean mOriginalPressedState; /** * The classification of the long click being checked: one of the - * StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. + * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. */ private int mClassification; @@ -28125,7 +28126,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } // To avoid negatively impacting View performance, the latency and displacement metrics // are omitted. - StatsLog.write(StatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), classification); + FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), + classification); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2b4b71f01aa5..435c9113a7e8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1691,7 +1691,7 @@ public final class ViewRootImpl implements ViewParent, .build(); setBoundsLayerCrop(); mTransaction.show(mBoundsLayer).apply(); - } + } return mBoundsLayer; } @@ -1699,7 +1699,9 @@ public final class ViewRootImpl implements ViewParent, if (mSurfaceControl == null || !mSurfaceControl.isValid()) { return null; } - if ((mBlastBufferQueue != null) && mBlastSurfaceControl.isValid()) { + if ((mBlastSurfaceControl != null) + && (mBlastBufferQueue == null) + && mBlastSurfaceControl.isValid()) { mBlastBufferQueue = new BLASTBufferQueue( mBlastSurfaceControl, width, height); } @@ -3348,7 +3350,6 @@ public final class ViewRootImpl implements ViewParent, private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { - mLayoutRequested = false; mScrollMayChange = true; mInLayout = true; diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 91778aaf51fd..62f3fa4f6ed4 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -41,9 +41,14 @@ public class WindowlessWindowManager implements IWindowSession { private class State { SurfaceControl mSurfaceControl; WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); - State(SurfaceControl sc, WindowManager.LayoutParams p) { + int mDisplayId; + IBinder mInputChannelToken; + State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, + IBinder inputChannelToken) { mSurfaceControl = sc; mParams.copyFrom(p); + mDisplayId = displayId; + mInputChannelToken = inputChannelToken; } }; @@ -105,19 +110,23 @@ public class WindowlessWindowManager implements IWindowSession { .setFormat(attrs.format) .setName(attrs.getTitle().toString()); final SurfaceControl sc = b.build(); - synchronized (this) { - mStateForWindow.put(window.asBinder(), new State(sc, attrs)); - } if (((attrs.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) { try { - mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, outInputChannel); + mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, + outInputChannel); } catch (RemoteException e) { - Log.e(TAG, "Failed to bless surface: " + e); + Log.e(TAG, "Failed to grant input to surface: ", e); } } + final State state = new State(sc, attrs, displayId, + outInputChannel != null ? outInputChannel.getToken() : null); + synchronized (this) { + mStateForWindow.put(window.asBinder(), state); + } + return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } @@ -162,7 +171,7 @@ public class WindowlessWindowManager implements IWindowSession { DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { - State state = null; + final State state; synchronized (this) { state = mStateForWindow.get(window.asBinder()); } @@ -173,8 +182,9 @@ public class WindowlessWindowManager implements IWindowSession { SurfaceControl sc = state.mSurfaceControl; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + int attrChanges = 0; if (inAttrs != null) { - state.mParams.copyFrom(inAttrs); + attrChanges = state.mParams.copyFrom(inAttrs); } WindowManager.LayoutParams attrs = state.mParams; @@ -197,6 +207,16 @@ public class WindowlessWindowManager implements IWindowSession { mergedConfiguration.setConfiguration(mConfiguration, mConfiguration); + if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0 + && state.mInputChannelToken != null) { + try { + mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc, + attrs.flags); + } catch (RemoteException e) { + Log.e(TAG, "Failed to update surface input channel: ", e); + } + } + return 0; } @@ -353,7 +373,12 @@ public class WindowlessWindowManager implements IWindowSession { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, - IBinder hostInputToken, InputChannel outInputChannel) { + IBinder hostInputToken, int flags, InputChannel outInputChannel) { + } + + @Override + public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { } @Override diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 051534cc3eb1..bbb751359bab 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -359,7 +359,7 @@ public class ResolverActivity extends Activity implements mMultiProfilePagerAdapter.getPersonalListAdapter()); mPersonalPackageMonitor.register( this, getMainLooper(), getPersonalProfileUserHandle(), false); - if (hasWorkProfile()) { + if (hasWorkProfile() && ENABLE_TABBED_VIEW) { mWorkPackageMonitor = createPackageMonitor( mMultiProfilePagerAdapter.getWorkListAdapter()); mWorkPackageMonitor.register(this, getMainLooper(), getWorkProfileUserHandle(), false); @@ -725,7 +725,7 @@ public class ResolverActivity extends Activity implements if (!mRegistered) { mPersonalPackageMonitor.register(this, getMainLooper(), getPersonalProfileUserHandle(), false); - if (hasWorkProfile()) { + if (hasWorkProfile() && ENABLE_TABBED_VIEW) { if (mWorkPackageMonitor == null) { mWorkPackageMonitor = createPackageMonitor( mMultiProfilePagerAdapter.getWorkListAdapter()); @@ -1155,7 +1155,9 @@ public class ResolverActivity extends Activity implements } private void safelyStartActivityInternal(TargetInfo cti) { - mPersonalPackageMonitor.unregister(); + if (mPersonalPackageMonitor != null) { + mPersonalPackageMonitor.unregister(); + } if (mWorkPackageMonitor != null) { mWorkPackageMonitor.unregister(); } diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java index e0eb9af8b228..5e886a611913 100644 --- a/core/java/com/android/internal/compat/ChangeReporter.java +++ b/core/java/com/android/internal/compat/ChangeReporter.java @@ -16,13 +16,16 @@ package com.android.internal.compat; +import android.annotation.IntDef; import android.util.Log; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -42,7 +45,7 @@ public final class ChangeReporter { long mChangeId; int mState; - ChangeReport(long changeId, int state) { + ChangeReport(long changeId, @State int state) { mChangeId = changeId; mState = state; } @@ -69,7 +72,7 @@ public final class ChangeReporter { // When true will of every time to debug (logcat). private boolean mDebugLogAll; - public ChangeReporter(int source) { + public ChangeReporter(@Source int source) { mSource = source; mReportedChanges = new HashMap<>(); mDebugLogAll = false; @@ -85,8 +88,8 @@ public final class ChangeReporter { */ public void reportChange(int uid, long changeId, int state) { if (shouldWriteToStatsLog(uid, changeId, state)) { - StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId, - state, mSource); + FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, + changeId, state, mSource); } if (shouldWriteToDebug(uid, changeId, state)) { debugLog(uid, changeId, state); @@ -110,7 +113,7 @@ public final class ChangeReporter { /** - * Returns whether the next report should be logged to statsLog. + * Returns whether the next report should be logged to FrameworkStatsLog. * * @param uid affected by the change * @param changeId the reported change id @@ -174,7 +177,7 @@ public final class ChangeReporter { private void debugLog(int uid, long changeId, int state) { String message = String.format("Compat change id reported: %d; UID %d; state: %s", changeId, uid, stateToString(state)); - if (mSource == StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER) { + if (mSource == SOURCE_SYSTEM_SERVER) { Slog.d(TAG, message); } else { Log.d(TAG, message); @@ -183,21 +186,56 @@ public final class ChangeReporter { } /** - * Transforms StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE enum to a string. + * Transforms {@link #ChangeReporter.State} enum to a string. * * @param state to transform * @return a string representing the state */ - private static String stateToString(int state) { + private static String stateToString(@State int state) { switch (state) { - case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED: + case STATE_LOGGED: return "LOGGED"; - case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED: + case STATE_ENABLED: return "ENABLED"; - case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED: + case STATE_DISABLED: return "DISABLED"; default: return "UNKNOWN"; } } + + /** These values should be kept in sync with those in atoms.proto */ + public static final int STATE_UNKNOWN_STATE = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__UNKNOWN_STATE; + public static final int STATE_ENABLED = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED; + public static final int STATE_DISABLED = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED; + public static final int STATE_LOGGED = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED; + public static final int SOURCE_UNKNOWN_SOURCE = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__UNKNOWN_SOURCE; + public static final int SOURCE_APP_PROCESS = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS; + public static final int SOURCE_SYSTEM_SERVER = + FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "STATE_" }, value = { + STATE_UNKNOWN_STATE, + STATE_ENABLED, + STATE_DISABLED, + STATE_LOGGED + }) + public @interface State { + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "SOURCE_" }, value = { + SOURCE_UNKNOWN_SOURCE, + SOURCE_APP_PROCESS, + SOURCE_SYSTEM_SERVER + }) + public @interface Source { + } } diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index ed04fd83a515..140c410e8de6 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -19,10 +19,10 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.metrics.LogMaker; import android.os.Build; -import android.util.StatsLog; import android.view.View; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FrameworkStatsLog; /** * Writes sysui_multi_event records to the system event log. @@ -55,8 +55,8 @@ public class MetricsLogger { protected void saveLog(LogMaker log) { // TODO(b/116684537): Flag guard logging to event log and statsd socket. EventLogTags.writeSysuiMultiAction(log.serialize()); - StatsLog.write(StatsLog.KEY_VALUE_PAIRS_ATOM, /* UID is retrieved from statsd side */ 0, - log.getEntries()); + FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM, + /* UID is retrieved from statsd side */ 0, log.getEntries()); } public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN; diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java index fe758a8e6cb7..785b2edf2e1b 100644 --- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java +++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java @@ -16,10 +16,10 @@ package com.android.internal.logging; -import android.util.StatsLog; +import com.android.internal.util.FrameworkStatsLog; /** - * Standard implementation of UiEventLogger, writing to StatsLog. + * Standard implementation of UiEventLogger, writing to FrameworkStatsLog. * * See UiEventReported atom in atoms.proto for more context. */ @@ -33,7 +33,7 @@ public class UiEventLoggerImpl implements UiEventLogger { public void log(UiEventEnum event, int uid, String packageName) { final int eventID = event.getId(); if (eventID > 0) { - StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, uid, packageName); + FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName); } } @@ -42,7 +42,7 @@ public class UiEventLoggerImpl implements UiEventLogger { InstanceId instance) { final int eventID = event.getId(); if (eventID > 0) { - StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, uid, packageName, + FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName, instance.getId()); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 580c1f00d788..18066dce287e 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -85,7 +85,6 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseLongArray; -import android.util.StatsLog; import android.util.TimeUtils; import android.util.Xml; import android.view.Display; @@ -100,6 +99,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeRea import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; import libcore.util.EmptyArray; @@ -4263,13 +4263,13 @@ public class BatteryStatsImpl extends BatteryStats { getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime); if (wc != null) { - StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), - getPowerManagerWakeLockLevel(type), name, - StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); + FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), + wc.getTags(), getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } else { - StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null, - getPowerManagerWakeLockLevel(type), name, - StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, + null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); } } } @@ -4308,13 +4308,13 @@ public class BatteryStatsImpl extends BatteryStats { getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime); if (wc != null) { - StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), - getPowerManagerWakeLockLevel(type), name, - StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); + FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), + wc.getTags(), getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } else { - StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null, - getPowerManagerWakeLockLevel(type), name, - StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, + null, getPowerManagerWakeLockLevel(type), name, + FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); } } } @@ -4323,7 +4323,8 @@ public class BatteryStatsImpl extends BatteryStats { * Converts BatteryStats wakelock types back into PowerManager wakelock levels. * This is the inverse map of Notifier.getBatteryStatsWakeLockMonitorType(). * These are estimations, since batterystats loses some of the original data. - * TODO: Delete this. Instead, StatsLog.write should be called from PowerManager's Notifier. + * TODO: Delete this. Instead, FrameworkStatsLog.write should be called from + * PowerManager's Notifier. */ private int getPowerManagerWakeLockLevel(int battertStatsWakelockType) { switch (battertStatsWakelockType) { @@ -4516,7 +4517,7 @@ public class BatteryStatsImpl extends BatteryStats { long deltaUptime = uptimeMs - mLastWakeupUptimeMs; SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason); timer.add(deltaUptime * 1000, 1); // time in in microseconds - StatsLog.write(StatsLog.KERNEL_WAKEUP_REPORTED, mLastWakeupReason, + FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_REPORTED, mLastWakeupReason, /* duration_usec */ deltaUptime * 1000); mLastWakeupReason = null; } @@ -4658,12 +4659,12 @@ public class BatteryStatsImpl extends BatteryStats { mGpsNesting++; if (workChain == null) { - StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, - StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null, + FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON); } else { - StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(), workChain.getTags(), - StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON); + FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON); } getUidStatsLocked(uid).noteStartGps(elapsedRealtime); @@ -4684,11 +4685,11 @@ public class BatteryStatsImpl extends BatteryStats { } if (workChain == null) { - StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, - StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null, + FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF); } else { - StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(), - workChain.getTags(), StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF); + FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(), + workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF); } getUidStatsLocked(uid).noteStopGps(elapsedRealtime); @@ -4947,9 +4948,10 @@ public class BatteryStatsImpl extends BatteryStats { mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtime); } addHistoryRecordLocked(elapsedRealtime, uptime); - StatsLog.write(StatsLog.BATTERY_SAVER_MODE_STATE_CHANGED, enabled ? - StatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON : - StatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF); + FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED, + enabled + ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON + : FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF); } } @@ -4977,7 +4979,7 @@ public class BatteryStatsImpl extends BatteryStats { if (nowIdling) statsmode = DEVICE_IDLE_MODE_DEEP; else if (nowLightIdling) statsmode = DEVICE_IDLE_MODE_LIGHT; else statsmode = DEVICE_IDLE_MODE_OFF; - StatsLog.write(StatsLog.DEVICE_IDLING_MODE_STATE_CHANGED, statsmode); + FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLING_MODE_STATE_CHANGED, statsmode); } if (mDeviceIdling != nowIdling) { mDeviceIdling = nowIdling; @@ -5023,7 +5025,7 @@ public class BatteryStatsImpl extends BatteryStats { mDeviceIdleModeFullTimer.startRunningLocked(elapsedRealtime); } mDeviceIdleMode = mode; - StatsLog.write(StatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mode); + FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mode); } } @@ -5197,7 +5199,8 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: " + Integer.toHexString(mHistoryCur.states)); mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime); - StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin); + FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, + simState, strengthBin); } } @@ -5209,7 +5212,8 @@ public class BatteryStatsImpl extends BatteryStats { + Integer.toHexString(mHistoryCur.states)); newHistory = true; mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime); - StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin); + FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state, + simState, strengthBin); } } @@ -5236,7 +5240,8 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: " + Integer.toHexString(mHistoryCur.states)); newHistory = true; - StatsLog.write(StatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin); + FrameworkStatsLog.write( + FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin); } else { stopAllPhoneSignalStrengthTimersLocked(-1); } @@ -12436,13 +12441,13 @@ public class BatteryStatsImpl extends BatteryStats { final int status, final int plugType, final int level) { if (recentPast == null || recentPast.batteryStatus != status) { - StatsLog.write(StatsLog.CHARGING_STATE_CHANGED, status); + FrameworkStatsLog.write(FrameworkStatsLog.CHARGING_STATE_CHANGED, status); } if (recentPast == null || recentPast.batteryPlugType != plugType) { - StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED, plugType); + FrameworkStatsLog.write(FrameworkStatsLog.PLUGGED_STATE_CHANGED, plugType); } if (recentPast == null || recentPast.batteryLevel != level) { - StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, level); + FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_LEVEL_CHANGED, level); } } diff --git a/core/java/com/android/internal/os/StatsdHiddenApiUsageLogger.java b/core/java/com/android/internal/os/StatsdHiddenApiUsageLogger.java index c169b2239554..89773b3feac7 100644 --- a/core/java/com/android/internal/os/StatsdHiddenApiUsageLogger.java +++ b/core/java/com/android/internal/os/StatsdHiddenApiUsageLogger.java @@ -18,10 +18,10 @@ package com.android.internal.os; import android.metrics.LogMaker; import android.os.Process; -import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FrameworkStatsLog; import dalvik.system.VMRuntime.HiddenApiUsageLogger; @@ -84,23 +84,24 @@ class StatsdHiddenApiUsageLogger implements HiddenApiUsageLogger { } private void newLogUsage(String signature, int accessMethod, boolean accessDenied) { - int accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE; + int accessMethodProto = FrameworkStatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE; switch(accessMethod) { case HiddenApiUsageLogger.ACCESS_METHOD_NONE: - accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE; + accessMethodProto = FrameworkStatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE; break; case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION: - accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__REFLECTION; + accessMethodProto = FrameworkStatsLog.HIDDEN_API_USED__ACCESS_METHOD__REFLECTION; break; case HiddenApiUsageLogger.ACCESS_METHOD_JNI: - accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__JNI; + accessMethodProto = FrameworkStatsLog.HIDDEN_API_USED__ACCESS_METHOD__JNI; break; case HiddenApiUsageLogger.ACCESS_METHOD_LINKING: - accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__LINKING; + accessMethodProto = FrameworkStatsLog.HIDDEN_API_USED__ACCESS_METHOD__LINKING; break; } int uid = Process.myUid(); - StatsLog.write(StatsLog.HIDDEN_API_USED, uid, signature, accessMethodProto, accessDenied); + FrameworkStatsLog.write(FrameworkStatsLog.HIDDEN_API_USED, uid, signature, + accessMethodProto, accessDenied); } } diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java index 8bb1e48201bb..ba60fa590792 100644 --- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java +++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java @@ -20,11 +20,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Pair; -import android.util.StatsLog; import android.view.WindowManager.LayoutParams; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FrameworkStatsLog; /** * Used to wrap different logging calls in one, so that client side code base is clean and more @@ -39,10 +39,10 @@ public class MetricsLoggerWrapper { Pair<ComponentName, Integer> topActivityInfo) { MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED, METRIC_VALUE_DISMISSED_BY_TAP); - StatsLog.write(StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, getUid(context, topActivityInfo.first, topActivityInfo.second), topActivityInfo.first.flattenToString(), - StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); + FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); } public static void logPictureInPictureDismissByDrag(Context context, @@ -50,20 +50,20 @@ public class MetricsLoggerWrapper { MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED, METRIC_VALUE_DISMISSED_BY_DRAG); - StatsLog.write(StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, getUid(context, topActivityInfo.first, topActivityInfo.second), topActivityInfo.first.flattenToString(), - StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); + FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); } public static void logPictureInPictureMinimize(Context context, boolean isMinimized, Pair<ComponentName, Integer> topActivityInfo) { MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED, isMinimized); - StatsLog.write(StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, getUid(context, topActivityInfo.first, topActivityInfo.second), topActivityInfo.first.flattenToString(), - StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED); + FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED); } /** @@ -92,29 +92,29 @@ public class MetricsLoggerWrapper { int uid, String shortComponentName, boolean supportsEnterPipOnTaskSwitch) { MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED, supportsEnterPipOnTaskSwitch); - StatsLog.write(StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid, + FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid, shortComponentName, - StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED); + FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED); } public static void logPictureInPictureFullScreen(Context context, int uid, String shortComponentName) { MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN); - StatsLog.write(StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid, shortComponentName, - StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN); + FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN); } public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) { if (changed) { if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) { - StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, true, - StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED); + FrameworkStatsLog.write(FrameworkStatsLog.OVERLAY_STATE_CHANGED, uid, packageName, + true, FrameworkStatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED); } else if (!usingAlertWindow){ - StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, false, - StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED); + FrameworkStatsLog.write(FrameworkStatsLog.OVERLAY_STATE_CHANGED, uid, packageName, + false, FrameworkStatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED); } } } @@ -122,11 +122,11 @@ public class MetricsLoggerWrapper { public static void logAppOverlayExit(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) { if (changed) { if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) { - StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, true, - StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED); + FrameworkStatsLog.write(FrameworkStatsLog.OVERLAY_STATE_CHANGED, uid, packageName, + true, FrameworkStatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED); } else if (!usingAlertWindow){ - StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, false, - StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED); + FrameworkStatsLog.write(FrameworkStatsLog.OVERLAY_STATE_CHANGED, uid, packageName, + false, FrameworkStatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED); } } } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index de02eb090391..e24e982bc9a8 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -89,4 +89,6 @@ interface ILockSettings { in List<WrappedApplicationKey> applicationKeys); void closeSession(in String sessionId); boolean hasSecureLockScreen(); + boolean tryUnlockWithCachedUnifiedChallenge(int userId); + void removeCachedUnifiedChallenge(int userId); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f37a46811b81..864429c98989 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -55,10 +55,10 @@ import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; -import libcore.util.HexEncoding; - import com.google.android.collect.Lists; +import libcore.util.HexEncoding; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.MessageDigest; @@ -1755,4 +1755,33 @@ public class LockPatternUtils { return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean( com.android.internal.R.bool.config_enableCredentialFactoryResetProtection); } + + /** + * Attempt to rederive the unified work challenge for the specified profile user and unlock the + * user. If successful, this would allow the user to leave quiet mode automatically without + * additional user authentication. + * + * This is made possible by the framework storing an encrypted copy of the unified challenge + * auth-bound to the primary user's lockscreen. As long as the primery user has unlocked + * recently (7 days), the framework will be able to decrypt it and plug the secret into the + * unlock flow. + * + * @return {@code true} if automatic unlocking is successful, {@code false} otherwise. + */ + public boolean tryUnlockWithCachedUnifiedChallenge(int userId) { + try { + return getLockSettings().tryUnlockWithCachedUnifiedChallenge(userId); + } catch (RemoteException re) { + return false; + } + } + + /** Remove cached unified profile challenge, for testing and CTS usage. */ + public void removeCachedUnifiedChallenge(int userId) { + try { + getLockSettings().removeCachedUnifiedChallenge(userId); + } catch (RemoteException re) { + re.rethrowFromSystemServer(); + } + } } diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index 31b5e491d0e5..ac2361dff560 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -35,14 +35,13 @@ import android.text.TextUtils; import android.util.AtomicFile; import android.util.EventLog; import android.util.Slog; -import android.util.StatsLog; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; -import com.android.server.DropboxLogTags; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -330,7 +329,7 @@ public class BootReceiver extends BroadcastReceiver { addTextToDropBox(db, "system_server_native_crash", text, filename, maxSize); } if (tag.equals(TAG_TOMBSTONE)) { - StatsLog.write(StatsLog.TOMB_STONE_OCCURRED); + FrameworkStatsLog.write(FrameworkStatsLog.TOMB_STONE_OCCURRED); } addTextToDropBox(db, tag, text, filename, maxSize); } @@ -427,20 +426,25 @@ public class BootReceiver extends BroadcastReceiver { int eventType; switch (propPostfix) { case "early": - eventType = StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_EARLY_DURATION; + eventType = + FrameworkStatsLog + .BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_EARLY_DURATION; break; case "default": eventType = - StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_DEFAULT_DURATION; + FrameworkStatsLog + .BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_DEFAULT_DURATION; break; case "late": - eventType = StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_LATE_DURATION; + eventType = + FrameworkStatsLog + .BOOT_TIME_EVENT_DURATION__EVENT__MOUNT_LATE_DURATION; break; default: continue; } - StatsLog.write(StatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, eventType, - duration); + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, + eventType, duration); } } } @@ -544,7 +548,8 @@ public class BootReceiver extends BroadcastReceiver { Slog.e(TAG, "No value received for shutdown duration"); } - StatsLog.write(StatsLog.SHUTDOWN_SEQUENCE_REPORTED, reboot, reason, start, duration); + FrameworkStatsLog.write(FrameworkStatsLog.SHUTDOWN_SEQUENCE_REPORTED, reboot, reason, start, + duration); } private static void logFsShutdownTime() { @@ -571,19 +576,19 @@ public class BootReceiver extends BroadcastReceiver { Pattern pattern = Pattern.compile(LAST_SHUTDOWN_TIME_PATTERN, Pattern.MULTILINE); Matcher matcher = pattern.matcher(lines); if (matcher.find()) { - StatsLog.write(StatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, - StatsLog.BOOT_TIME_EVENT_DURATION__EVENT__SHUTDOWN_DURATION, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED, + FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__SHUTDOWN_DURATION, Integer.parseInt(matcher.group(1))); - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, - StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, + FrameworkStatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT, Integer.parseInt(matcher.group(2))); Slog.i(TAG, "boot_fs_shutdown," + matcher.group(1) + "," + matcher.group(2)); } else { // not found // This can happen when a device has too much kernel log after file system unmount // ,exceeding maxReadSize. And having that much kernel logging can affect overall // performance as well. So it is better to fix the kernel to reduce the amount of log. - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, - StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, + FrameworkStatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__SHUTDOWN_UMOUNT_STAT, UMOUNT_STATUS_NOT_AVAILABLE); Slog.w(TAG, "boot_fs_shutdown, string not found"); } @@ -694,8 +699,9 @@ public class BootReceiver extends BroadcastReceiver { } stat = fixFsckFsStat(partition, stat, lines, startLineNumber, endLineNumber); if ("userdata".equals(partition) || "data".equals(partition)) { - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, - StatsLog.BOOT_TIME_EVENT_ERROR_CODE__EVENT__FS_MGR_FS_STAT_DATA_PARTITION, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ERROR_CODE_REPORTED, + FrameworkStatsLog + .BOOT_TIME_EVENT_ERROR_CODE__EVENT__FS_MGR_FS_STAT_DATA_PARTITION, stat); } Slog.i(TAG, "fs_stat, partition:" + partition + " stat:0x" + Integer.toHexString(stat)); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index c04efa3be596..cec68df3c949 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -137,6 +137,7 @@ cc_library_shared { "android_os_Parcel.cpp", "android_os_SELinux.cpp", "android_os_SharedMemory.cpp", + "android_os_storage_StorageManager.cpp", "android_os_Trace.cpp", "android_os_UEventObserver.cpp", "android_os_VintfObject.cpp", @@ -268,6 +269,7 @@ cc_library_shared { "libnativewindow", "libdl", "libdl_android", + "libstats_jni", "libstatslog", "server_configurable_flags", ], diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 924cd8153726..481be241cc99 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -108,6 +108,7 @@ namespace android { extern int register_android_app_admin_SecurityLog(JNIEnv* env); extern int register_android_content_AssetManager(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); +extern int register_android_util_StatsLog(JNIEnv* env); extern int register_android_util_StatsLogInternal(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_MemoryIntArray(JNIEnv* env); @@ -143,6 +144,7 @@ extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); extern int register_android_os_VintfObject(JNIEnv *env); extern int register_android_os_VintfRuntimeInfo(JNIEnv *env); +extern int register_android_os_storage_StorageManager(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); @@ -1445,6 +1447,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_MemoryIntArray), + REG_JNI(register_android_util_StatsLog), REG_JNI(register_android_util_StatsLogInternal), REG_JNI(register_android_app_admin_SecurityLog), REG_JNI(register_android_content_AssetManager), @@ -1466,6 +1469,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_HwParcel), REG_JNI(register_android_os_HwRemoteBinder), REG_JNI(register_android_os_NativeHandle), + REG_JNI(register_android_os_storage_StorageManager), REG_JNI(register_android_os_VintfObject), REG_JNI(register_android_os_VintfRuntimeInfo), REG_JNI(register_android_service_DataLoaderService), diff --git a/core/jni/android_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp new file mode 100644 index 000000000000..aee6733ecf53 --- /dev/null +++ b/core/jni/android_os_storage_StorageManager.cpp @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#define LOG_TAG "StorageManager" +#include <android-base/logging.h> +#include <android-base/unique_fd.h> +#include <fcntl.h> +#include <linux/fs.h> + +#include <nativehelper/JNIHelp.h> +#include "core_jni_helpers.h" + +namespace android { + +jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self, + jstring path, jlong projectId) { + struct fsxattr fsx; + ScopedUtfChars utf_chars_path(env, path); + + if (projectId > UINT32_MAX) { + LOG(ERROR) << "Invalid project id: " << projectId; + return JNI_FALSE; + } + + android::base::unique_fd fd( + TEMP_FAILURE_RETRY(open(utf_chars_path.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << utf_chars_path.c_str() << " to set project id."; + return JNI_FALSE; + } + + int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); + if (ret == -1) { + PLOG(ERROR) << "Failed to get extended attributes for " << utf_chars_path.c_str() + << " to get project id."; + return JNI_FALSE; + } + + fsx.fsx_projid = projectId; + ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx); + if (ret == -1) { + PLOG(ERROR) << "Failed to set extended attributes for " << utf_chars_path.c_str() + << " to set project id."; + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------------- + +static const JNINativeMethod gStorageManagerMethods[] = { + {"setQuotaProjectId", "(Ljava/lang/String;J)Z", + (void*)android_os_storage_StorageManager_setQuotaProjectId}, +}; + +const char* const kStorageManagerPathName = "android/os/storage/StorageManager"; + +int register_android_os_storage_StorageManager(JNIEnv* env) { + return RegisterMethodsOrDie(env, kStorageManagerPathName, gStorageManagerMethods, + NELEM(gStorageManagerMethods)); +} + +}; // namespace android diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 538861e21d96..a8246c7d84b7 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -151,11 +151,11 @@ static jboolean android_view_RenderNode_setOutlineRoundRect(CRITICAL_JNI_PARAMS_ return true; } -static jboolean android_view_RenderNode_setOutlineConvexPath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, +static jboolean android_view_RenderNode_setOutlinePath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr, jlong outlinePathPtr, jfloat alpha) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr); - renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath, alpha); + renderNode->mutateStagingProperties().mutableOutline().setPath(outlinePath, alpha); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); return true; } @@ -684,7 +684,7 @@ static const JNINativeMethod gMethods[] = { { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, { "nSetOutlineRoundRect", "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect }, - { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath }, + { "nSetOutlinePath", "(JJF)Z", (void*) android_view_RenderNode_setOutlinePath }, { "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty }, { "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone }, { "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 2b9d45431582..f564d7558832 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -22,20 +22,22 @@ #include "android_hardware_input_InputWindowHandle.h" #include "core_jni_helpers.h" +#include <memory> + +#include <android-base/chrono_utils.h> #include <android/graphics/region.h> #include <android_runtime/AndroidRuntime.h> -#include <android-base/chrono_utils.h> -#include <nativehelper/JNIHelp.h> -#include <nativehelper/ScopedUtfChars.h> #include <android_runtime/android_view_Surface.h> #include <android_runtime/android_view_SurfaceSession.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <jni.h> -#include <memory> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedUtfChars.h> #include <stdio.h> #include <system/graphics.h> #include <ui/ConfigStoreTypes.h> +#include <ui/DisplayConfig.h> #include <ui/DisplayInfo.h> #include <ui/DisplayedFrameStats.h> #include <ui/FrameStats.h> @@ -63,16 +65,21 @@ static const char* const OutOfResourcesException = static struct { jclass clazz; jmethodID ctor; + jfieldID density; + jfieldID secure; +} gDisplayInfoClassInfo; + +static struct { + jclass clazz; + jmethodID ctor; jfieldID width; jfieldID height; - jfieldID refreshRate; - jfieldID density; jfieldID xDpi; jfieldID yDpi; - jfieldID secure; + jfieldID refreshRate; jfieldID appVsyncOffsetNanos; jfieldID presentationDeadlineNanos; -} gPhysicalDisplayInfoClassInfo; +} gDisplayConfigClassInfo; static struct { jfieldID bottom; @@ -766,37 +773,46 @@ static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, } } -static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, - jobject tokenObj) { - sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); - if (token == NULL) return NULL; +static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) { + DisplayInfo info; + if (const auto token = ibinderForJavaObject(env, tokenObj); + !token || SurfaceComposerClient::getDisplayInfo(token, &info) != NO_ERROR) { + return nullptr; + } - Vector<DisplayInfo> configs; - if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR || - configs.size() == 0) { - return NULL; + jobject object = env->NewObject(gDisplayInfoClassInfo.clazz, gDisplayInfoClassInfo.ctor); + env->SetFloatField(object, gDisplayInfoClassInfo.density, info.density); + env->SetBooleanField(object, gDisplayInfoClassInfo.secure, info.secure); + return object; +} + +static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) { + Vector<DisplayConfig> configs; + if (const auto token = ibinderForJavaObject(env, tokenObj); !token || + SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR || + configs.isEmpty()) { + return nullptr; } - jobjectArray configArray = env->NewObjectArray(configs.size(), - gPhysicalDisplayInfoClassInfo.clazz, NULL); + jobjectArray configArray = + env->NewObjectArray(configs.size(), gDisplayConfigClassInfo.clazz, nullptr); for (size_t c = 0; c < configs.size(); ++c) { - const DisplayInfo& info = configs[c]; - jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz, - gPhysicalDisplayInfoClassInfo.ctor); - env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w); - env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h); - env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps); - env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density); - env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi); - env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi); - env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure); - env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos, - info.appVsyncOffset); - env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos, - info.presentationDeadline); - env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj); - env->DeleteLocalRef(infoObj); + const DisplayConfig& config = configs[c]; + jobject object = + env->NewObject(gDisplayConfigClassInfo.clazz, gDisplayConfigClassInfo.ctor); + env->SetIntField(object, gDisplayConfigClassInfo.width, config.resolution.getWidth()); + env->SetIntField(object, gDisplayConfigClassInfo.height, config.resolution.getHeight()); + env->SetFloatField(object, gDisplayConfigClassInfo.xDpi, config.xDpi); + env->SetFloatField(object, gDisplayConfigClassInfo.yDpi, config.yDpi); + + env->SetFloatField(object, gDisplayConfigClassInfo.refreshRate, config.refreshRate); + env->SetLongField(object, gDisplayConfigClassInfo.appVsyncOffsetNanos, + config.appVsyncOffset); + env->SetLongField(object, gDisplayConfigClassInfo.presentationDeadlineNanos, + config.presentationDeadline); + env->SetObjectArrayElement(configArray, static_cast<jsize>(c), object); + env->DeleteLocalRef(object); } return configArray; @@ -1409,7 +1425,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetDisplayProjection }, {"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V", (void*)nativeSetDisplaySize }, - {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;", + {"nativeGetDisplayInfo", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayInfo;", + (void*)nativeGetDisplayInfo }, + {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayConfig;", (void*)nativeGetDisplayConfigs }, {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I", (void*)nativeGetActiveConfig }, @@ -1507,21 +1525,24 @@ int register_android_view_SurfaceControl(JNIEnv* env) int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl", sSurfaceControlMethods, NELEM(sSurfaceControlMethods)); - jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo"); - gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); - gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, - gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V"); - gPhysicalDisplayInfoClassInfo.width = GetFieldIDOrDie(env, clazz, "width", "I"); - gPhysicalDisplayInfoClassInfo.height = GetFieldIDOrDie(env, clazz, "height", "I"); - gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F"); - gPhysicalDisplayInfoClassInfo.density = GetFieldIDOrDie(env, clazz, "density", "F"); - gPhysicalDisplayInfoClassInfo.xDpi = GetFieldIDOrDie(env, clazz, "xDpi", "F"); - gPhysicalDisplayInfoClassInfo.yDpi = GetFieldIDOrDie(env, clazz, "yDpi", "F"); - gPhysicalDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, clazz, "secure", "Z"); - gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env, - clazz, "appVsyncOffsetNanos", "J"); - gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env, - clazz, "presentationDeadlineNanos", "J"); + jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayInfo"); + gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz); + gDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V"); + gDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F"); + gDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z"); + + jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig"); + gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz); + gDisplayConfigClassInfo.ctor = GetMethodIDOrDie(env, configClazz, "<init>", "()V"); + gDisplayConfigClassInfo.width = GetFieldIDOrDie(env, configClazz, "width", "I"); + gDisplayConfigClassInfo.height = GetFieldIDOrDie(env, configClazz, "height", "I"); + gDisplayConfigClassInfo.xDpi = GetFieldIDOrDie(env, configClazz, "xDpi", "F"); + gDisplayConfigClassInfo.yDpi = GetFieldIDOrDie(env, configClazz, "yDpi", "F"); + gDisplayConfigClassInfo.refreshRate = GetFieldIDOrDie(env, configClazz, "refreshRate", "F"); + gDisplayConfigClassInfo.appVsyncOffsetNanos = + GetFieldIDOrDie(env, configClazz, "appVsyncOffsetNanos", "J"); + gDisplayConfigClassInfo.presentationDeadlineNanos = + GetFieldIDOrDie(env, configClazz, "presentationDeadlineNanos", "J"); jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect"); gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I"); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 1ea7d6144356..92941b8cb22b 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -820,6 +820,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, if (isFuse) { if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) { const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id); + PrepareDir(pass_through_source, 0710, AID_ROOT, AID_MEDIA_RW, fail_fn); BindMount(pass_through_source, "/storage", fail_fn); } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) { const std::string installer_source = StringPrintf("/mnt/installer/%d", user_id); diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 1426932ec04a..0a2fd7093a49 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -55,87 +55,8 @@ message ActivityManagerServiceProto { message ActivityManagerServiceDumpActivitiesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional ActivityStackSupervisorProto activity_stack_supervisor = 1; -} - -message ActivityStackSupervisorProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; - repeated ActivityDisplayProto displays = 2; - optional KeyguardControllerProto keyguard_controller = 3; - // TODO(b/111541062): Focused stack and resumed activity are now per-display. Topmost instances - // can be obtained from top display and these fields can be removed. - optional int32 focused_stack_id = 4; - optional .com.android.server.wm.IdentifierProto resumed_activity = 5; - // Whether or not the home activity is the recents activity. This is needed for the CTS tests to - // know what activity types to check for when invoking splitscreen multi-window. - optional bool is_home_recents_component = 6; - repeated .com.android.server.wm.IdentifierProto pending_activities = 7; - optional .com.android.server.wm.RootWindowContainerProto root_window_container = 8; -} - -/* represents ActivityStackSupervisor.ActivityDisplay */ -message ActivityDisplayProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // To be removed soon. - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; - optional int32 id = 2; - repeated ActivityStackProto stacks = 3; - optional int32 focused_stack_id = 4; - optional .com.android.server.wm.IdentifierProto resumed_activity = 5; - optional bool single_task_instance = 6; - optional .com.android.server.wm.DisplayContentProto display = 7; -} - -message ActivityStackProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // To be removed soon. - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; - optional int32 id = 2; - repeated TaskRecordProto tasks = 3; - optional .com.android.server.wm.IdentifierProto resumed_activity = 4; - optional int32 display_id = 5; - optional bool fullscreen = 6; - optional .android.graphics.RectProto bounds = 7; - optional .com.android.server.wm.StackProto stack = 8; -} - -message TaskRecordProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // To be removed soon. - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; - optional int32 id = 2; - repeated .com.android.server.wm.ActivityRecordProto activities = 3; - optional int32 stack_id = 4; - optional .android.graphics.RectProto last_non_fullscreen_bounds = 5; - optional string real_activity = 6; - optional string orig_activity = 7; - optional int32 activity_type = 8; - optional int32 resize_mode = 9; - optional bool fullscreen = 10; - optional .android.graphics.RectProto bounds = 11; - optional int32 min_width = 12; - optional int32 min_height = 13; - optional .com.android.server.wm.TaskProto task = 14; -} - -message KeyguardControllerProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional bool keyguard_showing = 1; - repeated KeyguardOccludedProto keyguard_occluded_states= 2; - optional bool aod_showing = 3; -} - -message KeyguardOccludedProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional int32 display_id = 1; - optional bool keyguard_occluded = 2; + reserved 1; // activity_stack_supervisor + optional .com.android.server.wm.RootWindowContainerProto root_window_container = 2; } // "dumpsys activity --proto broadcasts" @@ -669,8 +590,6 @@ message ActivityManagerServiceDumpProcessesProto { optional int64 previous_proc_visible_time_ms = 17; optional ProcessRecordProto heavy_weight_proc = 18; optional .android.content.ConfigurationProto global_configuration = 19; - // ActivityStackSupervisorProto dumps these values as well, still here? - // repeated ActivityDisplayProto displays = 20; optional bool config_will_change = 21; diff --git a/core/proto/android/server/vibratorservice.proto b/core/proto/android/server/vibratorservice.proto new file mode 100644 index 000000000000..281a25e55dc2 --- /dev/null +++ b/core/proto/android/server/vibratorservice.proto @@ -0,0 +1,66 @@ +/* + * 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. + */ + +syntax = "proto2"; +package com.android.server; + +option java_multiple_files = true; + +import "frameworks/base/core/proto/android/privacy.proto"; + +message WaveformProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + repeated int32 timings = 1; + repeated int32 amplitudes = 2; + required bool repeat = 3; +} + +message PrebakedProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + optional int32 effect_id = 1; + optional int32 effect_strength = 2; + optional int32 fallback = 3; +} + +// A com.android.os.VibrationEffect object. +message VibrationEffectProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + optional WaveformProto waveform = 1; + optional PrebakedProto prebaked = 2; +} + +message VibrationProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + optional int64 start_time = 1; + optional VibrationEffectProto effect = 2; + optional VibrationEffectProto origin_effect = 3; +} + +message VibratorServiceDumpProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + optional VibrationProto current_vibration = 1; + optional bool is_vibrating = 2; + optional VibrationProto current_external_vibration = 3; + optional bool vibrator_under_external_control = 4; + optional bool low_power_mode = 5; + optional int32 haptic_feedback_intensity = 6; + optional int32 notification_intensity = 7; + optional int32 ring_intensity = 8; + repeated VibrationProto previous_ring_vibrations = 9; + repeated VibrationProto previous_notification_vibrations = 10; + repeated VibrationProto previous_alarm_vibrations = 11; + repeated VibrationProto previous_vibrations = 12; +}
\ No newline at end of file diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 7c8f62c14b1e..b0b9ce6f9968 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -54,8 +54,14 @@ message RootWindowContainerProto { optional WindowContainerProto window_container = 1; repeated DisplayContentProto displays = 2; + reserved 3; // IdentifierProto windows /* window references in top down z order */ - repeated IdentifierProto windows = 3; + repeated WindowStateProto windows = 4; + optional KeyguardControllerProto keyguard_controller = 5; + // Whether or not the home activity is the recents activity. This is needed for the CTS tests to + // know what activity types to check for when invoking splitscreen multi-window. + optional bool is_home_recents_component = 6; + repeated IdentifierProto pending_activities = 7; } message BarControllerProto { @@ -94,6 +100,21 @@ message KeyguardServiceDelegateProto { optional InteractiveState interactive_state = 5; } +message KeyguardControllerProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional bool keyguard_showing = 1; + repeated KeyguardOccludedProto keyguard_occluded_states = 2; + optional bool aod_showing = 3; +} + +message KeyguardOccludedProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 display_id = 1; + optional bool keyguard_occluded = 2; +} + /* represents PhoneWindowManager */ message WindowManagerPolicyProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -145,7 +166,7 @@ message DisplayContentProto { optional WindowContainerProto window_container = 1; optional int32 id = 2; - repeated StackProto stacks = 3; + reserved 3; // stacks optional DockedStackDividerControllerProto docked_stack_divider_controller = 4; // Will be removed soon. optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true]; @@ -166,6 +187,12 @@ message DisplayContentProto { repeated IdentifierProto changing_apps = 19; repeated WindowTokenProto overlay_windows = 20; optional DisplayAreaProto root_display_area = 21; + + + optional bool single_task_instance = 22; + optional int32 focused_root_task_id = 23; + optional .com.android.server.wm.IdentifierProto resumed_activity = 24; + repeated TaskProto tasks = 25; } /* represents DisplayArea object */ @@ -191,7 +218,6 @@ message DisplayAreaChildProto { repeated string unknown = 3; } - /* represents DisplayFrames */ message DisplayFramesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -214,39 +240,41 @@ message PinnedStackControllerProto { optional .android.graphics.RectProto movement_bounds = 2 [deprecated=true]; } -/* represents TaskStack */ -message StackProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional WindowContainerProto window_container = 1; - optional int32 id = 2; - repeated TaskProto tasks = 3; - optional bool fills_parent = 4; - optional .android.graphics.RectProto bounds = 5; - optional bool animation_background_surface_is_dimming = 6 [deprecated=true]; - optional bool defer_removal = 7; - optional float minimize_amount = 8; - optional bool adjusted_for_ime = 9; - optional float adjust_ime_amount = 10; - optional float adjust_divider_amount = 11; - optional .android.graphics.RectProto adjusted_bounds = 12; - optional bool animating_bounds = 13; -} - /* represents Task */ message TaskProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional WindowContainerProto window_container = 1; optional int32 id = 2; - repeated ActivityRecordProto activity = 3; + reserved 3; // activity optional bool fills_parent = 4; optional .android.graphics.RectProto bounds = 5; optional .android.graphics.RectProto displayed_bounds = 6; - // Will be removed soon. - optional bool defer_removal = 7 [deprecated=true]; + optional bool defer_removal = 7; optional int32 surface_width = 8; optional int32 surface_height = 9; + + repeated TaskProto tasks = 10; + repeated ActivityRecordProto activities = 11; + + optional .com.android.server.wm.IdentifierProto resumed_activity = 12; + optional string real_activity = 13; + optional string orig_activity = 14; + + optional int32 display_id = 15; + optional int32 root_task_id = 16; + optional int32 activity_type = 17; + optional int32 resize_mode = 18; + optional int32 min_width = 19; + optional int32 min_height = 20; + + optional .android.graphics.RectProto adjusted_bounds = 21; + optional .android.graphics.RectProto last_non_fullscreen_bounds = 22; + optional bool adjusted_for_ime = 23; + optional float adjust_ime_amount = 24; + optional float adjust_divider_amount = 25; + optional bool animating_bounds = 26; + optional float minimize_amount = 27; } /* represents ActivityRecordProto */ @@ -271,17 +299,15 @@ message ActivityRecordProto { optional int32 num_drawn_windows = 15; optional bool all_drawn = 16; optional bool last_all_drawn = 17; - // Will be removed soon - optional bool removed = 18 [deprecated=true]; + reserved 18; // removed optional IdentifierProto starting_window = 19; optional bool starting_displayed = 20; - optional bool starting_moved = 21; + optional bool starting_moved = 201; optional bool visible_set_from_transferred_starting_window = 22; repeated .android.graphics.RectProto frozen_bounds = 23; optional bool visible = 24; - // To be removed soon. - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 25 [deprecated=true]; - optional .com.android.server.wm.IdentifierProto identifier = 26; + reserved 25; // configuration_container + optional IdentifierProto identifier = 26; optional string state = 27; optional bool front_of_task = 28; optional int32 proc_id = 29; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3a1b63d56b5f..6df0161c3ca6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3672,6 +3672,10 @@ <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY" android:protectionLevel="signature|installer" /> + <!-- @hide Allows an application to upgrade runtime permissions. --> + <permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to whitelist restricted permissions on any of the whitelists. @hide --> @@ -4234,7 +4238,7 @@ <!-- @SystemApi @TestApi @hide Allows managing apk level rollbacks. --> <permission android:name="android.permission.MANAGE_ROLLBACKS" - android:protectionLevel="signature|verifier" /> + android:protectionLevel="signature|privileged" /> <!-- @TestApi @hide Allows testing apk level rollbacks. --> <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" diff --git a/core/res/res/drawable/media_seamless_background.xml b/core/res/res/drawable/media_seamless_background.xml index aec89e0e8980..9b470cbe096f 100644 --- a/core/res/res/drawable/media_seamless_background.xml +++ b/core/res/res/drawable/media_seamless_background.xml @@ -20,7 +20,7 @@ <item android:id="@android:id/background"> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#1f000000"/> - <corners android:radius="20dp"/> + <corners android:radius="24dp"/> </shape> </item> </ripple> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index c34a485bc7a9..d6c5a1379a58 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Persoonlike programme is deur \'n administrateur opgeskort"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tik hier om voldoening aan beleid te kontroleer."</string> <string name="me" msgid="6207584824693813140">"Ek"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-opsies"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-opsies"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Verwyder"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Die voorgronddiens wat in die agtergrond begin het vanaf <xliff:g id="PACKAGENAME">%1$s</xliff:g> sal nie ingebruik-toestemming hê in toekomstige R-bouweergawes nie. Raadpleeg asseblief go/r-bg-fgs-restriction en dien \'n foutverslag in."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word.\n\n Bestaande toeganklikheidkenmerk:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Jy kan die kenmerk in Instellings > Toeganklikheid verander."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Program is nie beskikbaar nie"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nie nou onmiddellik beskikbaar nie. Dit word bestuur deur <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Kom meer te wete"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Hervat program"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Skakel werkprofiel aan?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jou werkprogramme, kennisgewings, data en ander werkprofielkenmerke sal aangeskakel word"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Wissel verdeelde skerm"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Toeganklikheid-kieslys"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlik"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 23e6ccdbd87f..e9409fbf92ed 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string> <string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"የግል መተግበሪያዎች በአስተዳዳሪ ታግዷል"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"የመመሪያ ተገዥነትን ለመፈተሽ እዚህ ላይ መለያ ያድርጉ።"</string> <string name="me" msgid="6207584824693813140">"እኔ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"የጡባዊ አማራጮች"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV አማራጮች"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"አስወግድ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ዳራው ከ<xliff:g id="PACKAGENAME">%1$s</xliff:g> የጀመረው የፊት አገልግሎት ወደፊት በሚኖሩት R ግንቦች ላይ ጥቅም ላይ እየዋለ ፈቃድ አይኖረውም። እባክዎ go/r-bg-fgs-restriction እና ፋይል ሳንካ ሪፖርትን ይመልከቱ።"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"የተደራሽነት አቋራጭ ጥቅም ላይ ይዋል?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"አቋራጩ ሲበራ ሁለቱንም የድምፅ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።\n\n አሁን ያለ የተደራሽነት ባህሪ፦\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ባህሪውን በቅንብሮች > ተደራሽነት ውስጥ ሊለውጡት ይችላሉ።"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"መተግበሪያ አይገኝም"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> አሁን ላይ አይገኝም። በ<xliff:g id="APP_NAME_1">%2$s</xliff:g> የሚተዳደር ነው።"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"የበለጠ ለመረዳት"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"መተግበሪያን ላፍታ እንዳይቆም አድርግ"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"የስራ መገለጫ ይብራ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"የእርስዎ የስራ መተግበሪያዎች፣ ማሳወቂያዎች፣ ውሂብ እና ሌሎች የስራ መገለጫ ባህሪያት ይበራሉ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"አብራ"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"የተከፈለ ማያን ቀያይር"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"የተደራሽነት ምናሌ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"የግል"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ሥራ"</string> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 80c04ebee695..23ffd7b6594a 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -202,10 +202,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string> <string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"علّق المشرف عمل التطبيقات الشخصية"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"انقر هنا للتحقّق من الالتزام بالسياسات."</string> <string name="me" msgid="6207584824693813140">"أنا"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"خيارات الجهاز اللوحي"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"خيارات Android TV"</string> @@ -1701,8 +1699,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"إزالة"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"لن يتم منح إذن الوصول إلى الموقع الجغرافي أثناء الاستخدام للخدمات التي تعمل في المقدّمة من <xliff:g id="PACKAGENAME">%1$s</xliff:g> والتي تبدأ من الخلفية في إصدارات R القادمة. يُرجى مراجعة go/r-bg-fgs-restriction وتقديم تقرير خطأ."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"هل تريد استخدام اختصار \"سهولة الاستخدام\"؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"عند تشغيل الاختصار، يؤدي الضغط على زرّي مستوى الصوت لمدة 3 ثوانٍ إلى تفعيل ميزة \"سهولة الاستخدام\".\n\n ميزة \"سهولة الاستخدام\" الحالية:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n يمكنك تغيير الميزة من \"الإعدادات\" > \"سهولة الاستخدام\"."</string> @@ -1980,8 +1977,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"التطبيق غير متاح"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"التطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> غير متاح الآن، وهو مُدار بواسطة <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"مزيد من المعلومات"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"استئناف تشغيل التطبيق"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"تفعيل الملف الشخصي للعمل؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"تشغيل"</string> @@ -2121,7 +2117,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"جدول بيانات: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"عرض تقديمي"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"عرض تقديمي: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> - <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"سيظل البلوتوث مفعَّلاً أثناء تفعيل \"وضع الطائرة\"."</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"سيظل البلوتوث مفعَّلاً أثناء استخدام \"وضع الطائرة\"."</string> <string name="car_loading_profile" msgid="8219978381196748070">"جارٍ التحميل"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="zero"><xliff:g id="FILE_NAME_2">%s</xliff:g> و<xliff:g id="COUNT_3">%d</xliff:g> ملف</item> @@ -2143,12 +2139,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تبديل \"تقسيم الشاشة\""</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"قائمة \"سهولة الاستخدام\""</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 73e32b85c224..a09c377d45b9 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string> <string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ব্যক্তিগত এপ্সমূহ এগৰাকী প্ৰশাসকে নিলম্বিত কৰিছে"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"নীতি মানি চলেনে নাই পৰীক্ষা কৰিবলৈ ইয়াত টিপক।"</string> <string name="me" msgid="6207584824693813140">"মই"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"টে\'বলেটৰ বিকল্পসমূহ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVৰ বিকল্পসমূহ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"আঁতৰাওক"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"নেপথ্যই <xliff:g id="PACKAGENAME">%1$s</xliff:g>ৰ পৰা আৰম্ভ কৰা অগ্ৰভূমিৰ সেৱাটোৰ ভৱিষ্যতৰ R বিল্ডসমূহত ব্যৱহাৰ হৈ থকা সম্পৰ্কীয় অনুমতি নাথাকিব। অনুগ্ৰহ কৰি go/r-bg-fgs-restriction চাওক আৰু এটা বাগৰিপ\'ৰ্ট ফাইল কৰক।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"শ্বৰ্টকাট অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটামত ৩ ছেকেণ্ডৰ বাবে ছাপ দি থাকিলে দিব্যাংগসকলৰ বাবে থকা সুবিধা এটা আৰম্ভ হ\'ব। \n\n চলিত দিব্যাংগসকলৰ সুবিধা:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপুনি এই সুবিধাটো ছেটিংসমূহ > দিব্যাংগসকলৰ বাবে সুবিধা-লৈ গৈ সলনি কৰিব পাৰে।"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"এপটো নাই"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"অধিক জানক"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"এপ্ আনপজ কৰক"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"কৰ্মস্থানৰ প্ৰ\'ফাইল অন কৰিবনে?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"আপোনাৰ কৰ্মস্থানৰ এপসমূহ, জাননীসমূহ, ডেটা আৰু কৰ্মস্থানৰ প্ৰ\'ফাইলৰ অইন সুবিধাসমূহ অন কৰা হ\'ব"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"বিভাজিত স্ক্ৰীন ট’গল কৰক"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"সাধ্য সুবিধাৰ মেনু"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index c894c29956dc..b1209b100633 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Şəxsi tətbiqlər admin tərəfindən dayandırılıb"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Siyasətə uyğunluğu yoxlamaq üçün bura toxunun."</string> <string name="me" msgid="6207584824693813140">"Mən"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planşet seçimləri"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçimləri"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Siz artıq modeli <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%2$d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində yenidən cəhd edin."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Yığışdır"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Arxa fonda başladılan <xliff:g id="PACKAGENAME">%1$s</xliff:g> üzrə ön plan xidmətinin gələcək R versiyalarında \"istifadə zamanı\" icazəsi olmayacaq. go/r-bg-fgs-restriction bölməsinə keçin və baq hesabatı göndərin."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Qısayol aktiv olduqda hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası işə başlayacaq.\n\n Cari əlçatımlılıq funksiyası:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funksiyanı Ayarlar və Əçatımlılıq bölməsində dəyişə bilərsiniz."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Tətbiq əlçatmazdır"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hazırda əlçatan deyil. Bunu <xliff:g id="APP_NAME_1">%2$s</xliff:g> idarə edir."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ətraflı məlumat"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Tətbiqi davam etdirin"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"İş profili aktiv edilsin?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"İş tətbiqləri, bildirişləri, data və digər iş profili funksiyaları aktiv ediləcək"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekrana keçid"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Əlçatımlılıq Menyusu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 909c31558e18..5600882ca16f 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrator je suspendovao lične aplikacije"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovde da biste proverili usklađenost sa smernicama."</string> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije za tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string> @@ -1635,8 +1633,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde/i."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prvom planu sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> koja je pokrenuta u pozadini neće imati dozvolu tokom korišćenja u budućim R verzijama. Posetite go/r-bg-fgs-restriction i pošaljite izveštaj o grešci."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti.\n\n Aktuelna funkcija pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Možete da promenite funkciju u odeljku Podešavanja > Pristupačnost."</string> @@ -1884,8 +1881,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. <xliff:g id="APP_NAME_1">%2$s</xliff:g> upravlja dostupnošću."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opozovi pauziranje aplikacije"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo profil za Work?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije profila za Work"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> @@ -2041,12 +2037,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite/isključite podeljeni ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni Pristupačnost"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 19dcf927b74d..fb80e4b043b9 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Асабістыя праграмы заблакіраваны адміністратарам"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Націсніце тут, каб упэўніцца ў адпаведнасці правілам."</string> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Параметры планшэта"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Параметры Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Выдалiць"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Запушчаны ў фонавым рэжыме асноўны сэрвіс з пакета \"<xliff:g id="PACKAGENAME">%1$s</xliff:g>\" не будзе мець дазволу while-in-use у будучых зборках на мове R. Наведайце сайт go/r-bg-fgs-restriction і адпраўце справаздачу пра памылку."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Калі камбінацыя хуткага доступу ўключана, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб уключыць функцыю спецыяльных магчымасцей.\n\n Бягучая функцыя спецыяльных магчымасцей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Вы можаце змяніць гэту функцыю ў меню \"Налады > Спецыяльныя магчымасці\"."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Праграма недаступная"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" цяпер недаступная. Яна кіруецца праграмай \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Даведацца больш"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Скасаваць прыпыненне для праграмы"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Уключыць працоўны профіль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Будуць уключаны вашы рабочыя праграмы, апавяшчэнні, даныя і іншыя функцыі працоўнага профілю"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Уключыць"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Пераключальнік падзеленага экрана"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню спецыяльных магчымасцей"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 8a687666ac9b..2892853f0923 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Личните приложения може да са спрени от администратора"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Докоснете тук, за да проверите дали правилата ст спазват."</string> <string name="me" msgid="6207584824693813140">"Аз"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции за таблета"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции за Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Премахване"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Задният план, който е стартирал услуга на преден план от <xliff:g id="PACKAGENAME">%1$s</xliff:g>, няма да има разрешение при използване в бъдещите компилации R. Моля, вижте go/r-bg-fgs-restriction и подайте сигнал за програмна грешка."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Искате ли да използвате пряк път към функцията за достъпност?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за промяна на силата на звука и ги задържите 3 секунди.\n\n Текущата функция за достъпност е:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцията от „Настройки“ > „Достъпност“."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Няма достъп до приложението"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"В момента няма достъп до <xliff:g id="APP_NAME_0">%1$s</xliff:g>. Това се управлява от <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Научете повече"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Отмяна на паузата за приложението"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Вкл. на служ. потр. профил?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Служебните ви приложения, известия и данни, както и другите функции на служебния потребителски профил ще бъдат включени"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Включване"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Превключване на разделения екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню за достъпност"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 9ca383d30b04..4c95081cc15d 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string> <string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"অ্যাডমিন ব্যক্তিগত অ্যাপ সাসপেন্ড করেছেন"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"নীতি মেনে চলা হচ্ছে কিনা তা যাচাই করতে এখানে ট্যাপ করুন।"</string> <string name="me" msgid="6207584824693813140">"আমাকে"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ট্যাবলেট বিকল্পগুলি"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-র বিকল্প"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"সরান"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> থেকে শুরু হওয়া ফোরগ্রাউন্ড পরিষেবাটির ভবিষ্যতে আর বিল্ডগুলিতে ব্যবহারের অনুমতি নেই। go/r-bg-fgs-restriction দেখুন এবং বাগরিপোর্ট জমা দিন।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"অ্যাক্সেসযোগ্যতা শর্টকাট ব্যবহার করবেন?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"শর্টকাটটি চালু থাকলে দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি বৈশিষ্ট্য চালু হবে।\n\n বর্তমান অ্যাকসেসিবিলিটি বৈশিষ্ট্য:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপনি এই বৈশিষ্ট্যটি সেটিংস > অ্যাকসেসিবিলিটিতে গিয়ে পরিবর্তন করতে পারবেন।"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"অ্যাপটি উপলভ্য নয়"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> এখন উপলভ্য নয়। এই অ্যাপটিকে <xliff:g id="APP_NAME_1">%2$s</xliff:g> অ্যাপ ম্যানেজ করে।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"আরও জানুন"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"অ্যাপ আবার চালু করুন"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"কাজের প্রোফাইল চালু করবেন?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"আপনার কাজের অ্যাপ, বিজ্ঞপ্তি, ডেটা এবং কাজের প্রোফাইলের অন্যান্য বৈশিষ্ট্য চালু করা হবে"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"স্প্লিট স্ক্রিন টগল করুন"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"অ্যাক্সেসিবিলিটি মেনু"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 5f83aa427eef..eaa212dccf2f 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Lične aplikacije je obustavio administrator"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovdje da provjerite usklađenost s pravilima."</string> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tableta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV uređaja"</string> @@ -1637,8 +1635,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluge iz prvog plana započete u pozadini s web lokacije <xliff:g id="PACKAGENAME">%1$s</xliff:g> neće imati odobrenje za funkciju \"za vrijeme korištenja\" u budućim R verzijama. Pogledajte go/r-bg-fgs-restriction i podnesite izvještaj o greškama."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritiskom na oba dugmeta za podešavanje jačine zvuka u trajanju od 3 sekunde pokrenut će se funkcija za pristupačnost.\n\n Trenutna funkcija za pristupačnost je:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciju možete promijeniti ako odete u Postavke > Pristupačnost."</string> @@ -1886,8 +1883,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. Ovim upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Ponovo aktiviraj aplikaciju"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Uključiti radni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se poslovne aplikacije, obavještenja, podaci i druge funkcije radnog profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> @@ -2024,7 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> tabela"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacija"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentacija"</string> - <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen i u načinu rada u avionu"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen tokom načina rada u avionu"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Učitavanje"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fajl</item> @@ -2043,12 +2039,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključi/isključi podijeljeni ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni za pristupačnost"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 930065b02883..0b58caea91b8 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador ha suspès les aplicacions personals"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca per comprovar si es compleix la política."</string> <string name="me" msgid="6207584824693813140">"Mi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcions de la tauleta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcions d\'Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Elimina"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servei en primer pla (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) iniciat en segon pla no tindrà permís durant l\'ús en compilacions R posteriors. Consulta la pàgina go/r-bg-fgs-restriction i presenta un informe d\'errors."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si la drecera està activada, prem els dos botons de volum durant 3 segons, per iniciar una funció d\'accessibilitat.\n\n Funció d\'accessibilitat actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pots canviar la funció a Configuració > Accessibilitat."</string> @@ -1852,10 +1849,9 @@ <string name="app_suspended_title" msgid="888873445010322650">"L\'aplicació no està disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no està disponible en aquests moments. Aquesta opció es gestiona a <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Més informació"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reactiva l\'aplicació"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Activar el perfil professional?"</string> - <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions per a la feina, les notificacions, les dades i altres funcions del perfil professional"</string> + <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions de treball, les notificacions, les dades i altres funcions del perfil professional"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Commuta Pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú d\'accessibilitat"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 2c017dd52ee1..5874c2493041 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osobní aplikace byly pozastaveny administrátorem"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Klepnutím sem zkontrolujete soulad se zásadami."</string> <string name="me" msgid="6207584824693813140">"Já"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zařízení Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odebrat"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba v popředí z balíčku <xliff:g id="PACKAGENAME">%1$s</xliff:g>, která byla spuštěna na pozadí, v budoucích sestavenách typu R nebude mít oprávnění ke spuštění při používání. Přejděte na adresu go/r-bg-fgs-restriction a vyplňte zprávu o chybě."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti.\n\n Aktuální funkce přístupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkci můžete změnit v Nastavení > Přístupnost."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikace není k dispozici"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> momentálně není dostupná. Tato předvolba se spravuje v aplikaci <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Další informace"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Zrušit pozastavení aplikace"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Zapnout pracovní profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vaše pracovní aplikace, oznámení, data a ostatní funkce pracovního účtu budou zapnuty"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Přepnout rozdělenou obrazovku"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Nabídka usnadnění přístupu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 4ebea8947666..eb7ad1b9e48f 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"En administrator har suspenderet personlige apps."</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tryk her for at tjekke overholdelsen af politikker."</string> <string name="me" msgid="6207584824693813140">"Mig"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valgmuligheder for tabletcomputeren"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Valgmuligheder for Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjern"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Tjenesten i forgrunden fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der starter i baggrunden, vil i fremtidige R-builds ikke have tilladelse, mens den er i brug. Se go/r-bg-fgs-restriction, og indsend en fejlrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger > Hjælpefunktioner."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgængelig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Få flere oplysninger"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Afslut pause for app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Skal arbejdsprofilen slås til?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå Opdelt skærm til eller fra"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menuen Hjælpefunktioner"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 6fa0ac1791fa..6b01af1f3b08 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Private Apps wurden von einem Administrator gesperrt"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tippe hier, um die Einhaltung der Richtlinie zu prüfen."</string> <string name="me" msgid="6207584824693813140">"Eigene"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-Optionen"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-Optionen"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Entfernen"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Der Dienst im Vordergrund von <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der im Hintergrund gestartet wurde, hat in zukünftigen R-Builds keine Zugriffsberechtigung mehr während der Nutzung. Siehe dazu go/r-bg-fgs-restriction und reiche einen Fehlerbericht ein."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten.\n\n Aktuelle Bedienungshilfe:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kannst die Bedienungshilfe unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App nicht verfügbar"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ist momentan nicht verfügbar. Dies wird über die App \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\" verwaltet."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Weitere Informationen"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App-Pausierung aufheben"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Arbeitsprofil aktivieren?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Deine geschäftlichen Apps, Benachrichtigungen, Daten und andere Funktionen des Arbeitsprofils werden aktiviert"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"\"Bildschirm teilen\" ein-/ausschalten"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sperrbildschirm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menü \"Bedienungshilfen\""</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 81a16f28651c..61ca692aae16 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Οι προσωπικές εφαρμογές έχουν τεθεί σε αναστολή από έναν διαχειριστή"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Πατήστε εδώ για να ελέγξετε τη συμμόρφωση πολιτικής."</string> <string name="me" msgid="6207584824693813140">"Για εμένα"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Επιλογές tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Επιλογές Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Κατάργηση"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Η υπηρεσία στο προσκήνιο που ξεκίνησε από το παρασκήνιο από το πακέτο <xliff:g id="PACKAGENAME">%1$s</xliff:g> δεν θα έχει άδεια πρόσβασης μόνο κατά τη χρήση σε μελλοντικές εκδόσεις R. Ανατρέξτε στο go/r-bg-fgs-restriction και υποβάλετε αναφορά σφάλματος."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Να χρησιμοποιείται η συντόμευση προσβασιμότητας;"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας.\n\n Τρέχουσα λειτουργία προσβασιμότητας:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Μπορείτε να αλλάξετε τη λειτουργία από τις Ρυθμίσεις > Προσβασιμότητα."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Η εφαρμογή δεν είναι διαθέσιμη"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή. Η διαχείριση πραγματοποιείται από την εφαρμογή <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Μάθετε περισσότερα"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Κατάργηση παύσης εφαρμογής"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ενεργοποίηση προφίλ εργασίας;"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Οι εφαρμογές, οι ειδοποιήσεις και τα δεδομένα εργασίας σας, καθώς και άλλες λειτουργίες του προφίλ εργασίας, θα ενεργοποιηθούν"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ενεργοποίηση"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Εναλλαγή διαχωρισμού οθόνης"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Μενού προσβασιμότητας"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 87e0c902df8c..15a059f449f1 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 008ad8aec7fc..f3ab25afdf1e 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 87e0c902df8c..15a059f449f1 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 87e0c902df8c..15a059f449f1 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 777107a60820..871e528c8e94 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bugreport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available right now. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data, and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility Menu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 4335c2bf9f27..1cb9fde2956a 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador suspendió las apps personales"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Presiona aquí para consultar el cumplimiento de políticas."</string> <string name="me" msgid="6207584824693813140">"Yo"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones de tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminar"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio que pasó del segundo al primer plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permiso durante el uso en las próximas compilaciones de R. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cuando el acceso directo está activado, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Configuración > Accesibilidad."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"La app no está disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reanudar app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Se activaran las apps de trabajo, los datos, las notificaciones y otras funciones del perfil de trabajo"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidad"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 8d750caa6dba..d8509a331453 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador ha suspendido las aplicaciones personales"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca aquí para comprobar el cumplimiento de las políticas."</string> <string name="me" msgid="6207584824693813140">"Yo"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones del tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Quitar"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio en primer plano que se inició en segundo plano en <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permisos en compilaciones R futuras mientras se estén usando. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si el acceso directo está activado, pulsa los dos botones de volumen durante tres segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Ajustes > Accesibilidad."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"La aplicación no está disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anular pausa de aplicación"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Tus aplicaciones, notificaciones, datos y otras funciones del perfil de trabajo se activarán"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar la pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidad"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 7f423e935b47..2148c09f08ad 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administraator on isiklikud rakendused peatanud"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Eeskirjade järgimise kontrollimiseks puudutage siin."</string> <string name="me" msgid="6207584824693813140">"Mina"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tahvelarvuti valikud"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV valikud"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eemalda"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustal käitatud esiplaanil oleval teenusel paketist <xliff:g id="PACKAGENAME">%1$s</xliff:g> ei ole tulevastes R-järkudes luba „kui kasutuses”. Vaadake saiti go/r-bg-fgs-restriction ja esitage veaaruanne."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni.\n\n Praegune juurdepääsetavuse funktsioon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Saate seda funktsiooni muuta valikutega Seaded > Juurdepääsetavus."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Rakendus pole saadaval"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pole praegu saadaval. Seda haldab rakendus <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lisateave"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Jätka rakendust"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Kas lülitada tööprofiil sisse?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Teie töörakendused, märguanded, andmed ja muud tööprofiili funktsioonid lülitatakse sisse"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Vaheta jagatud ekraanikuva"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Juurdepääsetavuse menüü"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 9d014a3b875a..07bde5ee0648 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikazio pertsonalak desgaitu egin ditu administratzaile batek"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Sakatu hau gidalerroa gordetzen den egiaztatzeko."</string> <string name="me" msgid="6207584824693813140">"Ni"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV gailuaren aukerak"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Kendu"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> webgunearen atzeko planoak hasitako aurreko planoko zerbitzuak ez du izango erabili bitarteko baimenik etorkizuneko R konpilazioetan. Joan go/r-bg-fgs-restriction atalera eta egin akatsaren txostena."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea.\n\n Uneko erabilerraztasun-eginbidea:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Eginbidea aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikazioa ez dago erabilgarri"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ez dago erabilgarri une honetan. Haren erabilgarritasuna <xliff:g id="APP_NAME_1">%2$s</xliff:g> aplikazioak kudeatzen du."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lortu informazio gehiago"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Kendu pausaldia"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Laneko profila aktibatu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktibatu/Desaktibatu pantaila zatitua"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantaila blokeatua"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pantaila-argazkia"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Erabilerraztasun-menua"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 58ce7a7e547c..d65357b73ba0 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string> <string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"سرپرستْ برنامههای شخصی را به حالت تعلیق درآورد"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"برای بررسی مطابقت با خطمشی، اینجا ضربه بزنید."</string> <string name="me" msgid="6207584824693813140">"من"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"گزینههای رایانهٔ لوحی"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"گزینههای Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"حذف"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"سرویس پیشنمای <xliff:g id="PACKAGENAME">%1$s</xliff:g>، که در پسزمینه شروع شده، در ساختهای آتی R اجازهٔ حین استفاده نخواهد داشت. لطفاً به go/r-bg-fgs-restriction بروید و گزارش اشکال ارسال کنید."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش میدهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی میتواند به شنواییتان آسیب وارد کند."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"از میانبر دسترسپذیری استفاده شود؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"وقتی میانبر روشن است، اگر هر دو دکمه صدا را ۳ ثانیه فشار دهید یکی از قابلیتهای دسترسپذیری شروع میشود.\n\n قابلیت دسترسپذیری کنونی:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n میتوانید در «تنظیمات > دسترسپذیری»، قابلیت را تغییر دهید."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"برنامه در دسترس نیست"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> درحالحاضر در دسترس نیست. <xliff:g id="APP_NAME_1">%2$s</xliff:g> آن را مدیریت میکند."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"بیشتر بدانید"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"لغو توقف موقت برنامه"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"نمایه کاری روشن شود؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"برنامهها، اعلانها، دادهها و سایر قابلیتهای نمایه کاری شما روشن خواهد شد"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تغییر وضعیت صفحهٔ دونیمه"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"عکس صفحهنمایش"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"منوی دسترسپذیری"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصی"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"کاری"</string> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index e0f4ed49b6a3..17b3d33b4cf8 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Järjestelmänvalvoja on estänyt henkilökohtaisten sovellusten käytön"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Katso käytäntöjen noudattaminen napauttamalla tätä."</string> <string name="me" msgid="6207584824693813140">"Minä"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-laitteen asetukset"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ‑vaihtoehdot"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Poista"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustalla aloitettu etualan palvelu (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) ei ole käytön aikana sallittu R:n tulevissa versioissa. Lue go/r-bg-fgs-restriction ja lähetä virheraportti."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan.\n\n Tällä hetkellä valittu esteettömyystoiminto:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Voit vaihtaa toimintoa valitsemalla Asetukset > Esteettömyys."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Sovellus ei käytettävissä"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ei ole juuri nyt saatavilla. Tästä vastaa <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lue lisää"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Peru keskeytys"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Otetaanko työprofiili käyttöön?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Työsovellukset, ‑ilmoitukset, ‑tiedot ja muut työprofiiliominaisuudet otetaan käyttöön"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Jaettu näyttö päälle/pois"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Esteettömyysvalikko"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 5d99db170087..45b8613a1e6f 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Les applications personnelles ont été suspendues par un administrateur"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Touchez ici pour vérifier la conformité aux politiques."</string> <string name="me" msgid="6207584824693813140">"Moi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Options d\'Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Supprimer"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation pendant l\'utilisation dans les futures versions R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bogue."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité sous Paramètres > Accessibilité."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"L\'application n\'est pas accessible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas accessible pour le moment. Ceci est géré par <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Réactiver l\'application"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Activer le profil professionnel?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, vos notifications, vos données et les autres fonctionnalités de profil professionnel seront activées"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Basculer l\'écran partagé"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu d\'accessibilité"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 3f4f3e6549e4..c646aeb8d82d 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Les applications personnelles ont été suspendues par un administrateur"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Appuyez ici pour vérifier que les règles sont respectées."</string> <string name="me" msgid="6207584824693813140">"Moi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Options Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Supprimer"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan et provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation \"pendant l\'utilisation\" dans les futurs builds R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité dans Paramètres > Accessibilité."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Application indisponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas disponible pour le moment. Cette suspension est gérée par l\'application <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Débloquer l\'application"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Activer profil professionnel ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, notifications, données et d\'autres fonctionnalités de votre profil professionnel seront activées"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activer/Désactiver l\'écran partagé"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu d\'accessibilité"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 2e5052c134b1..2a2d7c4712b9 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador suspendeu as aplicacións persoais"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca aquí para comprobar o cumprimento da política."</string> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcións de Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminar"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Nas futuras compilacións R, o servizo en primeiro plano iniciado en segundo plano desde <xliff:g id="PACKAGENAME">%1$s</xliff:g> non terá permiso mentres estea en uso. Consulta go/r-bg-fgs-restriction e presenta un informe de erros."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade.\n\n Función de accesibilidade actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Podes cambiar a función en Configuración > Accesibilidade."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"A aplicación non está dispoñible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicación <xliff:g id="APP_NAME_0">%1$s</xliff:g> non está dispoñible neste momento. A dispoñibilidade está xestionada por <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Máis información"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Volver activar aplicación"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Activar o perfil de traballo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Activaranse as túas aplicacións de traballo, as notificacións, os datos e outras funcións do perfil de traballo"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar/desactivar pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidade"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 8081ef2709ba..aab09f751076 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string> <string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"વ્યવસ્થાપક દ્વારા વ્યક્તિગત ઍપ સ્થગિત કરવામાં આવી છે"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"નીતિનું પાલન થાય છે કે કેમ તે તપાસવા માટે અહીં ટૅપ કરો."</string> <string name="me" msgid="6207584824693813140">"હું"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ટેબ્લેટ વિકલ્પો"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVના વિકલ્પો"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી. હજી <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસ પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"દૂર કરો"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"બૅકગ્રાઉન્ડમાં શરૂ થયેલી <xliff:g id="PACKAGENAME">%1$s</xliff:g>ની ફોરગ્રાઉન્ડ સેવા પાસે ભવિષ્યની R બિલ્ડમાં ઉપયોગમાં હોય તે સમયની પરવાનગી હશે નહીં. કૃપા કરીને go/r-bg-fgs-restriction જુઓ અને ભૂલનો અહેવાલ દાખલ કરો."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરીએ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે.\n\n વર્તમાન ઍક્સેસિબિલિટી સુવિધા:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n તમે સેટિંગ્સ > ઍક્સેસિબિલિટીમાં જઈને આ સુવિધા બદલી શકો છો."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ઍપ ઉપલબ્ધ નથી"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ઍપ ફરી શરૂ કરો"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"કાર્યાલયની પ્રોફાઇલ ચાલુ કરીએ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી કાર્યાલયની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય કાર્યાલયની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"સ્ક્રીનને વિભાજિત કરવાની ક્રિયા ટૉગલ કરો"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ઍક્સેસિબિલિટી મેનૂ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 05efcd8942cb..e1bb060fbc76 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string> <string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"किसी एडमिन ने निजी ऐप्लिकेशन निलंबित कर दिए हैं"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"नीति का पालन किया जा रहा है या नहीं, इसकी जांच करने के लिए यहां टैप करें."</string> <string name="me" msgid="6207584824693813140">"मैं"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"टैबलेट विकल्प"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV डिवाइस में फ़ोन से जुड़े विकल्प"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"निकालें"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>से बैकग्राउंड में शुरू की गई फ़ॉरग्राउंड सेवा के लिए, भविष्य के R बिल्ड में \'इस्तेमाल के समय अनुमति दें\' की सुविधा नहीं होगी. कृपया go/r-bg-fgs-restriction देखें और गड़बड़ी की शिकायत करें."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर ज़्यादा समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"सुलभता शॉर्टकट का इस्तेमाल करना चाहते हैं?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"इस शॉर्टकट के चालू होने पर, दोनों वॉल्यूम बटनों को 3 सेकंड तक दबाने से सुलभता सुविधा शुरू हो जाएगी.\n\n मौजूदा सुलभता सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n आप इस सुविधा को सेटिंग > सुलभता पर जाकर बदल सकते हैं."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"यह ऐप्लिकेशन उपलब्ध नहीं है"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"फ़िलहाल <xliff:g id="APP_NAME_0">%1$s</xliff:g> उपलब्ध नहीं है. इसे <xliff:g id="APP_NAME_1">%2$s</xliff:g> के ज़रिए प्रबंधित किया जाता है."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ज़्यादा जानें"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ऐप्लिकेशन पर लगी रोक हटाएं"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"वर्क प्रोफ़ाइल चालू करें?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"आपके काम से जुड़े ऐप्लिकेशन, सूचनाएं, डेटा और वर्क प्रोफ़ाइल से जुड़ी दूसरी सुविधाएं चालू हो जाएंगी"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करें"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"स्प्लिट स्क्रीन पर टॉगल करें"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"सुलभता मेन्यू"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index e4cefe8149d7..383943429400 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrator je obustavio osobne aplikacije"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovdje da biste provjerili usklađenost s pravilima."</string> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tabletnog uređaja"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string> @@ -1635,8 +1633,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prednjem planu s <xliff:g id="PACKAGENAME">%1$s</xliff:g> pokrenuta u pozadini neće imati dopuštenje tijekom upotrebe u budućim R kompilacijama. Pogledajte go/r-bg-fgs-restriction i pošaljite izvješće o programskoj pogrešci."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je taj prečac uključen, pritiskom na obje tipke za glasnoću na 3 sekunde pokrenut će se značajka pristupačnosti.\n\n Trenutačna značajka pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Značajku možete promijeniti u Postavkama > Pristupačnost."</string> @@ -1884,8 +1881,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutačno nije dostupna. Ovime upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekini pauzu aplikacije"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Želite uključiti radni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se vaše radne aplikacije, obavijesti, podaci i druge značajke radnog profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> @@ -2041,12 +2037,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite ili isključite podijeljeni zaslon"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Izbornik pristupačnosti"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 08cb1c774b33..fcea1ec4975a 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string> <string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"A személyes alkalmazások adminisztrátori felfüggesztés alá kerültek"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Koppintson ide az irányelvek betartásának ellenőrzéséhez."</string> <string name="me" msgid="6207584824693813140">"Saját"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Táblagép beállításai"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV beállításai"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eltávolítás"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"A háttér által indított előtérben futó szolgáltatás (innen: <xliff:g id="PACKAGENAME">%1$s</xliff:g>) nem tartalmaz majd használat közbeni engedélyt a jövőbeli R buildekben. Kérjük, keresse fel a go/r-bg-fgs-restriction webhelyet, és jelentse a hibát."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ha be van kapcsolva a billentyűparancs, a két hangerőgomb 3 másodpercig tartó lenyomásával elindíthatja a kisegítő lehetőségek egyik funkcióját.\n\n A kisegítő lehetőségek jelenleg beállított funkciója:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n A funkciót a Beállítások > Kisegítő lehetőségek menüpontban módosíthatja."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Az alkalmazás nem áll rendelkezésre"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> alkalmazás jelenleg nem áll rendelkezésre. Ezt a(z) <xliff:g id="APP_NAME_1">%2$s</xliff:g> kezeli."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"További információ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Alkalmazás szüneteltetésének feloldása"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Bekapcsolja a munkaprofilt?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"A munkahelyi alkalmazások, értesítések, adatok és a munkaprofilhoz tartozó egyéb funkciók be lesznek kapcsolva"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Osztott képernyő be- vagy kikapcsolása"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Kisegítő lehetőségek menü"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 9d33f6b8e4fd..cbd754f15e29 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Անձնական հավելվածները կասեցվել են ադմինիստրատորի կողմից"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Հպեք այստեղ, որպեսզի ստուգեք՝ արդյոք որևէ կանոն չի խախտվել։"</string> <string name="me" msgid="6207584824693813140">"Իմ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Պլանշետի ընտրանքները"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-ի կարգավորումներ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%2$d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Հեռացնել"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ֆոնային ռեժիմում <xliff:g id="PACKAGENAME">%1$s</xliff:g>-ից գործարկված առաջին պլանի ծառայությունը հետագա R կառուցումներում թույլտվություն չի ունենա օգտագործման ընթացքում։ Անցեք go/r-bg-fgs-restriction էջ և հաղորդեք վրիպակի մասին։"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է։\n\n Մատչելիության ակտիվ գործառույթը՝\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Գործառույթը կարող եք փոփոխել՝ անցնելով Կարգավորումներ > Հատուկ գործառույթներ։"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Հավելվածը հասանելի չէ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածը հասանելի չէ։ Դրա աշխատանքը սահմանափակում է <xliff:g id="APP_NAME_1">%2$s</xliff:g> հավելվածը։"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Մանրամասն"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Չեղարկել դադարեցումը"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Միացնե՞լ աշխատանքային պրոֆիլը"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Միացնել/անջատել էկրանի տրոհումը"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Հատուկ գործառույթների ընտրացանկ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 48136108d7c1..f1a94ff0149e 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikasi pribadi telah ditangguhkan oleh admin"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ketuk di sini untuk memeriksa kepatuhan kebijakan."</string> <string name="me" msgid="6207584824693813140">"Saya"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsi tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsi Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Hapus"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Layanan latar depan yang dimulai oleh latar belakang dari <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan memiliki izin saat-sedang-digunakan pada build R masa mendatang Lihat go/r-bg-fgs-restriction dan kirim laporan bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas.\n\n Fitur aksesibilitas saat ini:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda dapat mengubah fitur di Setelan > Aksesibilitas."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikasi tidak tersedia"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saat ini tidak tersedia. Aplikasi ini dikelola oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Pelajari lebih lanjut"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Batalkan jeda aplikasi"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Aktifkan profil kerja?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikasi kerja, notifikasi, data, dan fitur profil kerja lainnya akan diaktifkan"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktifkan/Nonaktifkan Layar Terpisah"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Aksesibilitas"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Pribadi"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index bf3fe87f7931..b4cb76d367b5 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Stjórnandi hefur lokað á persónuleg forrit"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ýttu hér til að sjá reglufylgni."</string> <string name="me" msgid="6207584824693813140">"Ég"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valkostir spjaldtölvu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Valkostir Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjarlægja"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnsþjónusta frá <xliff:g id="PACKAGENAME">%1$s</xliff:g> sem er ræst úr bakgrunni mun ekki hafa heimild við notkun í framtíðarútgáfum R. Farðu á go/r-bg-fgs-restriction og gefðu villuskýrslu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur.\n\n Virkur aðgengiseiginleiki:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Hægt er að skipta um eiginleika í Stillingar > Aðgengi."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Forritið er ekki í boði"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ekki í boði eins og er. Þessu er stjórnað með <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Nánari upplýsingar"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Halda áfram að nota"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Kveikja á vinnusniði?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Kveikt verður á vinnuforritum, tilkynningum, gögnum og öðrum eiginleikum vinnusniðsins"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Breyta skjáskiptingu"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Aðgengisvalmynd"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 72ca138f9ed3..23a62a8a48f8 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Le app personali sono state sospese da un amministratore"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tocca qui per controllare il rispetto delle norme."</string> <string name="me" msgid="6207584824693813140">"Io"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opzioni tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opzioni Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Rimuovi"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Il servizio in primo piano avviato in background da <xliff:g id="PACKAGENAME">%1$s</xliff:g> non avrà l\'autorizzazione \"durante l\'uso\" nelle future build R. Visita la pagina go/r-bg-fgs-restriction e invia una segnalazione di bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità.\n\n Funzione di accessibilità corrente:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puoi cambiare la funzione in Impostazioni > Accessibilità."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App non disponibile"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> non è al momento disponibile. Viene gestita tramite <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ulteriori informazioni"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Riattiva app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Attivare il profilo di lavoro?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Le tue app di lavoro, le notifiche, i dati e altri elementi del profilo di lavoro saranno attivati."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Attiva/disattiva schermo diviso"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Accessibilità"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personale"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 9c8d0a3a64ec..4319aa8644f0 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string> <string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"אפליקציות אישיות הושעו על ידי מנהל מערכת"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"יש להקיש כאן כדי לבדוק תאימות למדיניות."</string> <string name="me" msgid="6207584824693813140">"אני"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"אפשרויות טאבלט"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"אפשרויות Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"הסר"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"לשירות שפועל בחזית מ-<xliff:g id="PACKAGENAME">%1$s</xliff:g> שהחל ברקע לא תהיה הרשאת while-in-use בגרסאות R build בעתיד. יש לעיין בכתובת go/r-bg-fgs-restriction ולהגיש דוח על באג."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת השמע למשך שלוש שניות מפעילה את תכונת הנגישות.\n\n תכונת הנגישות המוגדרת כרגע:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n אפשר לשנות את התכונה בקטע \'הגדרות ונגישות\'."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"האפליקציה אינה זמינה"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"האפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> לא זמינה כרגע. את הזמינות שלה אפשר לנהל באפליקציה <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"מידע נוסף"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ביטול ההשהיה של האפליקציה"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"להפעיל את פרופיל העבודה?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"אפליקציות העבודה, התראות, נתונים ותכונות נוספות של פרופיל העבודה יופעלו"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"הפעל"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"החלפת מצב של מסך מפוצל"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"תפריט נגישות"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 529d0119f0be..481af76de9a7 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string> <string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"個人用アプリは管理者によって停止されています"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ポリシー コンプライアンスを確認するにはここをタップしてください。"</string> <string name="me" msgid="6207584824693813140">"自分"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"タブレットオプション"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV のオプション"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%1$d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%2$d</xliff:g>回間違えると、モバイルデバイスのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>秒後にもう一度お試しください。"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"削除"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"今後の R ビルドでは、<xliff:g id="PACKAGENAME">%1$s</xliff:g> からバックグラウンドで開始されるフォアグラウンド サービスに「使用中のみ許可」の権限がありません。go/r-bg-fgs-restriction を確認し、バグレポートを提出してください。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ショートカットが ON の場合、両方の音量ボタンを 3 秒間押し続けるとユーザー補助機能が起動します。\n\n現在のユーザー補助機能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nユーザー補助機能は [設定] > [ユーザー補助] で変更できます。"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"このアプリは使用できません"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"現在、<xliff:g id="APP_NAME_0">%1$s</xliff:g> は使用できません。このアプリの使用は [<xliff:g id="APP_NAME_1">%2$s</xliff:g>] で管理されています。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"詳細"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"アプリの一時停止を解除"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"仕事用プロファイルの有効化"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"仕事用のアプリ、通知、データなど、仕事用プロファイルの機能が ON になります"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"分割画面の切り替え"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ユーザー補助機能メニュー"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 3f97338ade76..c2c28e515593 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"პირადი აპები შეჩერებულია ადმინისტრატორის მიერ"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"შეეხეთ აქ წესებთან შესაბამისობის შესამოწმებლად."</string> <string name="me" msgid="6207584824693813140">"მე"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ტაბლეტის პარამეტრები"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ვარიანტები"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ამოშლა"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-ის ფონურად დაწყებულ წინა პლანის სერვისს მომავალ R build-ებში გამოყენების პროცესში წვდომის ნებართვა არ ექნება. გთხოვთ, იხილოთ go/r-bg-fgs-restriction და გამოგზავნოთ ხარვეზის ანგარიში."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"გსურთ მარტივი წვდომის მალსახმობის გამოყენება?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"მალსახმობის ჩართვის შემთხვევაში, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება.\n\n მარტივი წვდომის ამჟამინდელი ფუნქციაა:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ამ ფუნქციის შეცვლა შეგიძლიათ აქ: პარამეტრები > მარტივი წვდომა."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"აპი მიუწვდომელია"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ამჟამად მიუწვდომელია. ის იმართება <xliff:g id="APP_NAME_1">%2$s</xliff:g>-ის მიერ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"შეიტყვეთ მეტი"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"აპის დაპაუზების გაუქმება"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ჩაირთოს სამსახურის პროფილი?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"თქვენი სამსახურის აპები, შეტყობინებები, მონაცემები და სამსახურის პროფილის ყველა სხვა ფუნქცია ჩაირთვება"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ჩართვა"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"გაყოფილი ეკრანის გადართვა"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"მარტივი წვდომის მენიუ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"პირადი"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"სამსახური"</string> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index bccd3f4b6a77..7cb05129495d 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Әкімші жеке қолданбаларды уақытша тоқтатты"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Саясат талаптарының сай келуін тексеру үшін осы жерді түртіңіз."</string> <string name="me" msgid="6207584824693813140">"Мен"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет опциялары"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV опциялары"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Алып тастау"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондық режимде іске қосылған <xliff:g id="PACKAGENAME">%1$s</xliff:g> белсенді пакетінің алдағы R құрамаларында \"Пайдаланғанда ғана рұқсат ету\" рұқсаты болмайды. go/r-bg-fgs-restriction бетіне өтіп, қате туралы есеп жіберіңіз."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Бұл төте жол қосулы кезде дыбыс деңгейі түймелерінің екеуін де 3 секунд бойы басқанда арнайы мүмкіндік іске қосылады.\n\n Ағымдағы арнайы мүмкіндік:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Бұл мүмкіндікті \"Параметрлер\" > \"Арнайы мүмкіндіктер\" тармағында өзгертуге болады."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Қолданба қолжетімді емес"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> дәл қазір қолжетімді емес. Ол <xliff:g id="APP_NAME_1">%2$s</xliff:g> арқылы басқарылады."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Толығырақ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Қолданбаны қайта қосу"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Жұмыс профилі қосылсын ба?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Жұмыс қолданбалары, хабарландырулар, деректер және басқа да жұмыс профильдерінің мүмкіндіктері қосылады"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлу мүмкіндігін қосу/өшіру"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Арнайы мүмкіндіктер мәзірі"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index ee451e936020..e0267d363721 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string> <string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"អ្នកគ្រប់គ្រងបានផ្អាកកម្មវិធីផ្ទាល់ខ្លួន"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ចុចត្រង់នេះ ដើម្បីពិនិត្យមើលការអនុលោមតាមគោលការណ៍។"</string> <string name="me" msgid="6207584824693813140">"ខ្ញុំ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ជម្រើសកុំព្យូទ័របន្ទះ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ជម្រើស Android TV"</string> @@ -1615,8 +1613,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%2$d</xliff:g> ដង អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរស័ព្ទរបស់អ្នកដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី។"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"លុបចេញ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"សេវាកម្មផ្ទៃខាងមុខដែលចាប់ផ្ដើមដោយផ្ទៃខាងក្រោយពី <xliff:g id="PACKAGENAME">%1$s</xliff:g> នឹងមិនមានការអនុញ្ញាតខណៈពេលកំពុងប្រើប្រាស់ទេ នៅក្នុងកំណែបង្កើត R នៅពេលអនាគត។ សូមមើល go/r-bg-fgs-restriction និងផ្ញើរបាយការណ៍អំពីបញ្ហា។"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"បង្កើនកម្រិតសំឡេងលើសពីកម្រិតបានផ្ដល់យោបល់?\n\nការស្ដាប់នៅកម្រិតសំឡេងខ្លាំងយូរអាចធ្វើឲ្យខូចត្រចៀក។"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ប្រើប្រាស់ផ្លូវកាត់ភាពងាយស្រួល?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"នៅពេលផ្លូវកាត់នេះបើក ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីរឲ្យជាប់រយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយស្រួល។\n\n មុខងារភាពងាយស្រួលបច្ចុប្បន្ន៖\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n អ្នកអាចផ្លាស់ប្តូរមុខងារនេះបាននៅក្នុងការ កំណត់ > ភាពងាយស្រួល។"</string> @@ -1854,8 +1851,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"កម្មវិធីមិនអាចប្រើបានទេ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> មិនអាចប្រើបានទេនៅពេលនេះ។ វាស្ថិតក្រោមការគ្រប់គ្រងរបស់ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ។"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ស្វែងយល់បន្ថែម"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ឈប់ផ្អាកកម្មវិធី"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"បើកកម្រងព័ត៌មានការងារ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"កម្មវិធីការងារ ការជូនដំណឹង ទិន្នន័យ និងមុខងារកម្រងព័ត៌មានការងារផ្សេងទៀតរបស់អ្នកនឹងត្រូវបានបើក"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"បើក"</string> @@ -2009,12 +2005,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"បិទ/បើកមុខងារបំបែកអេក្រង់"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ម៉ឺនុយភាពងាយស្រួល"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 75282842175c..4a2bc72d27d8 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್ಗಳನ್ನು ನಿರ್ವಾಹಕರು ಅಮಾನತುಗೊಳಿಸಿದ್ದಾರೆ"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ಕಾರ್ಯನೀತಿ ಅನುಸರಣೆಯನ್ನು ಪರಿಶೀಲಿಸಲು ಇಲ್ಲಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="me" msgid="6207584824693813140">"ನಾನು"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ಟ್ಯಾಬ್ಲೆಟ್ ಆಯ್ಕೆಗಳು"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ಆಯ್ಕೆಗಳು"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ತೆಗೆದುಹಾಕು"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ನಿಂದ ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಪ್ರಾರಂಭಿಸಲಾದ ಮುನ್ನೆಲೆ ಸೇವೆ ಭವಿಷ್ಯದ R ಬಿಲ್ಡ್ಗಳಿಂದ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಅನುಮತಿಯನ್ನು ಪಡೆಯುವುದಿಲ್ಲ. go/r-bg-fgs-restriction ಅನ್ನು ನೋಡಿ ಮತ್ತು ದೋಷವರದಿಯನ್ನು ಫೈಲ್ ಮಾಡಿ."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ವಾಲ್ಯೂಮ್ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಬಳಸುವುದೇ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ ಆನ್ ಮಾಡಲು, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು ನೀವು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಬೇಕು.\n\nಪ್ರಸ್ತುತ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ: \n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಪ್ರವೇಶಿಸುವಿಕೆಯಲ್ಲಿ ನೀವು ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬದಲಾಯಿಸಬಹುದು."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ. ಇದನ್ನು <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ಆ್ಯಪ್ ವಿರಾಮ ನಿಲ್ಲಿಸಿ"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಆನ್ ಮಾಡುವುದೇ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ನಿಮ್ಮ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳು, ಅಧಿಸೂಚನೆಗಳು, ಡೇಟಾ ಮತ್ತು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆನ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್ ಮಾಡಿ"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಟಾಗಲ್ ಮಾಡಿ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index d5b450757bf9..0ac7a1447f7c 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string> <string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"관리자가 개인 앱을 정지함"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"정책 준수를 확인하려면 여기를 탭하세요."</string> <string name="me" msgid="6207584824693813140">"나"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"태블릿 옵션"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 옵션"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"삭제"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"향후 R 빌드에서는 백그라운드에서 시작된 <xliff:g id="PACKAGENAME">%1$s</xliff:g>의 포그라운드 서비스에 더 이상 사용 중인 상태에서 필요한 권한이 부여되지 않습니다. go/r-bg-fgs-restriction 페이지에서 버그 신고를 제출하세요."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"단축키가 사용 설정된 경우 두 개의 볼륨 버튼을 3초간 누르면 접근성 기능이 시작됩니다.\n\n 현재 접근성 기능:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n \'설정 > 접근성\'에서 기능을 변경할 수 있습니다."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"앱을 사용할 수 없음"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>은(는) 현재 사용할 수 없습니다. <xliff:g id="APP_NAME_1">%2$s</xliff:g>에서 관리하는 앱입니다."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"자세히 알아보기"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"앱 일시중지 해제"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"직장 프로필을 사용 설정하시겠어요?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"업무용 앱, 알림, 데이터 및 기타 직장 프로필 기능이 사용 설정됩니다."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"화면 분할 모드 전환"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"접근성 메뉴"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 533e0b816142..88e36ff0b533 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Жеке колдонмолорду администратор убактылуу токтотту"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Саясатка ылайыктуулугун текшерүү үчүн бул жерди таптап коюңуз"</string> <string name="me" msgid="6207584824693813140">"Мен"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет мүмкүнчүлүктөрү"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV параметрлери"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес көрсөттүңүз. <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес көрсөтүлгөндөн кийин, телефондун кулпусун ачуу үчүн Google аккаунтуңузга кирүүгө туура келет.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин кайталап көрсөңүз болот."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Алып салуу"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондогу <xliff:g id="PACKAGENAME">%1$s</xliff:g> кызматы активдүү режимде иштеп баштап, кийинки R курамаларында колдонуу учурунда уруксаты болбойт. Төмөнкү бөлүмгө өтүп, мүчүлүштүк тууралуу кабарды тапшырыңыз: go/r-bg-fgs-restriction."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн, ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең үч секунддай кое бербей басып туруңуз.\n\n Учурдагы атайын мүмкүнчүлүктөрдүн жөндөөлөрү:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nЖөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнөн өзгөртө аласыз."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Колдонмо жеткиликсиз"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> колдонмосу учурда жеткиликсиз. Анын жеткиликтүүлүгү <xliff:g id="APP_NAME_1">%2$s</xliff:g> тарабынан башкарылат."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Кеңири маалымат"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Колдонмону иштетүү"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Жумуш профили күйгүзүлсүнбү?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Жумуш колдонмолоруңуз, эскертмелериңиз, дайын-даректериңиз жана жумуш профилинин башка функциялары күйгүзүлөт."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлүүнү күйгүзүү же өчүрүү"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Атайын мүмкүнчүлүктөр менюсу"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 7a3e85e7f5b2..63b87ac54e3e 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ແອັບສ່ວນຕົວຖືກລະງັບໄວ້ໂດຍຜູ້ເບິ່ງແຍງ"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ແຕະບ່ອນນີ້ເພື່ອກວດສອບການປະຕິບັດຕາມນະໂຍບາຍ."</string> <string name="me" msgid="6207584824693813140">"ຂ້າພະເຈົ້າ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ໂຕເລືອກແທັບເລັດ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ຕົວເລືອກ Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ລຶບອອກ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ບໍລິການພື້ນໜ້າທີ່ເລີ່ມຕົ້ນຈາກພື້ນຫຼັງຈາກ <xliff:g id="PACKAGENAME">%1$s</xliff:g> ຈະບໍ່ມີສິດອະນຸຍາດໃນຂະນະທີ່ໃຊ້ໃນ R builds ໃນອະນາຄົດ. ກະລຸນາອ່ານ go/r-bg-fgs-restriction ແລະ ລາຍງານຂໍ້ຜິດພາດ."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ເພີ່ມລະດັບສຽງໃຫ້ເກີນກວ່າລະດັບທີ່ແນະນຳບໍ?\n\nການຮັບຟັງສຽງໃນລະດັບທີ່ສູງເປັນໄລຍະເວລາດົນອາດເຮັດໃຫ້ການຟັງຂອງທ່ານມີບັນຫາໄດ້."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ເມື່ອເປີດໃຊ້ປຸ່ມລັດແລ້ວ, ໃຫ້ກົດປຸ່ມສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີເພື່ອເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ.\n\n ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງປັດຈຸບັນ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ທ່ານສາມາດປ່ຽນຄຸນສົມບັດໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ບໍ່ສາມາດໃຊ້ແອັບໄດ້"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້. ມັນຖືກຈັດການໂດຍ <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ສຶກສາເພີ່ມເຕີມ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ຍົກເລີກການຢຸດແອັບຊົ່ວຄາວ"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ເປີດໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ແອັບວຽກຂອງທ່ານ, ການແຈ້ງເຕືອນ, ຂໍ້ມູນ ແລະ ຄຸນສົມບັດໂປຣໄຟລ໌ວຽກຈະຖືກເປີດໃຊ້"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ເປີດ"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ເປີດ/ປິດການແບ່ງໜ້າຈໍ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ເມນູການຊ່ວຍເຂົ້າເຖິງ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ສ່ວນຕົວ"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ວຽກ"</string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 265c97e4b228..b8d848e91929 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administratorius laikinai sustabdė asmenines programas"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Palieskite čia, kad patikrintumėte, ar laikomasi politikos."</string> <string name="me" msgid="6207584824693813140">"Aš"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetinio kompiuterio parinktys"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"„Android TV“ parinktys"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Pašalinti"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fone pradėtai priekinio plano paslaugai iš „<xliff:g id="PACKAGENAME">%1$s</xliff:g>“ nebus suteiktas leidimas naudojimo metu būsimose R versijose. Apsilankykite go/r-bg-fgs-restriction ir pateikite pranešimą apie riktą."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kai spartusis klavišas įjungtas, spaudžiant abu garsumo mygtukus 3 sekundes bus paleista pritaikymo neįgaliesiems funkcija.\n\n Dabartinė pritaikymo neįgaliesiems funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>„\n“\n Funkciją galite pakeisti skiltyje „Nustatymai“ > „Pritaikymas neįgaliesiems“."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Programa nepasiekiama"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ šiuo metu nepasiekiama. Tai tvarkoma naudojant programą „<xliff:g id="APP_NAME_1">%2$s</xliff:g>“."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Sužinoti daugiau"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Atšaukti programos pristabdymą"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Įjungti darbo profilį?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Darbo programos, pranešimai, duomenys ir kitos darbo profilio funkcijos bus išjungtos"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Perjungti išskaidyto ekrano režimą"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Pritaikomumo meniu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index a535f6dd9feb..f168bb4121c8 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrators apturēja privāto lietotņu darbību"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Pieskarieties šeit, lai noskaidrotu atbilstību politikai."</string> <string name="me" msgid="6207584824693813140">"Man"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetdatora opcijas"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV opcijas"</string> @@ -1635,8 +1633,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundēm."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Noņemt"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonā sāktam priekšplāna pakalpojumam no pakotnes <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebūs atļaujas “while-in-use” turpmākajās R versijās. Lūdzu, skatiet vietni go/r-bg-fgs-restriction un iesniedziet kļūdas pārskatu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ja saīsne ir iespējota, vienlaikus nospiežot abas skaļuma regulēšanas pogas un trīs sekundes turot tās, tiks palaista pieejamības funkcija.\n\n Pašreiz iestatītā pieejamības funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Šo funkciju var mainīt sadaļā Iestatījumi > Pieejamība."</string> @@ -1884,8 +1881,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Lietotne nav pieejama"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pašlaik nav pieejama. Šo darbību pārvalda <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Uzzināt vairāk"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Atsākt lietotnes darbību"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Vai ieslēgt darba profilu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Tiks ieslēgtas jūsu darba lietotnes, paziņojumi, dati un citas darba profila funkcijas."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string> @@ -2041,12 +2037,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Pārslēgt ekrāna sadalīšanu"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Pieejamības izvēlne"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 2f75269cf421..f94d191fba28 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Администраторот ги суспендирал личните апликации"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Допрете тука за да ја проверите усогласеноста со правилата."</string> <string name="me" msgid="6207584824693813140">"Јас"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции на таблет"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции на Android TV"</string> @@ -1615,8 +1613,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Отстрани"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услугата од преден план започната во заднина од <xliff:g id="PACKAGENAME">%1$s</xliff:g> нема да има дозола за „додека се користи“ во идните R-верзии. Погледнете на go/r-bg-fgs-restriction и испратете извештај за грешка."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да го зголемиме звукот над препорачаното ниво?\n\nСлушањето звуци со голема јачина подолги периоди може да ви го оштети сетилото за слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Да се користи кратенка за „Пристапност“?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција на пристапност.\n\n Тековна функција на пристапност:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Функцијата може да ја промените во „Поставки“ > „Пристапност“."</string> @@ -1854,8 +1851,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апликацијата не е достапна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Апликацијата <xliff:g id="APP_NAME_0">%1$s</xliff:g> не е достапна во моментов. Со ова управува <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Дознај повеќе"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Прекини ја паузата"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Да се вклучи работниот профил?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Вашите работни апликации, известувања, податоци и други функции на работниот профил ќе бидат вклучени"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Вклучи"</string> @@ -2009,12 +2005,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Вклучи/исклучи поделен екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Мени за пристапност"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Службени"</string> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 25d72126418f..1efd21132ebc 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string> <string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"വ്യക്തഗത ആപ്പുകൾ ഒരു അഡ്മിൻ താൽക്കാലികമായി റദ്ദാക്കിയിരിക്കുന്നു"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"നയത്തിന് അനുസൃതമാണോ എന്ന് പരിശോധിക്കാൻ ഇവിടെ ടാപ്പ് ചെയ്യുക."</string> <string name="me" msgid="6207584824693813140">"ഞാന്"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ടാബ്ലെറ്റ് ഓപ്ഷനുകൾ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ടിവി ഓപ്ഷനുകൾ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"നീക്കംചെയ്യുക"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള പശ്ചാത്തലത്തിൽ ആരംഭിച്ച് ഫോർഗ്രൗണ്ടിൽ വരുന്ന സേവനത്തിന് ഭാവി R ബിൽഡുകളിൽ, \'ഉപയോഗിക്കുമ്പോൾ മാത്രമുള്ള അനുമതി\' ഉണ്ടായിരിക്കില്ല. go/r-bg-fgs-restriction കണ്ട് ബഗ് റിപ്പോർട്ട് ഫയൽ ചെയ്യുക."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കണോ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"കുറുക്കുവഴി ഓണാണെങ്കിൽ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും.\n\n നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ക്രമീകരണം > ഉപയോഗസഹായി എന്നതിൽ ഏത് സമയത്തും നിങ്ങൾക്ക് ഫീച്ചർ മാറ്റാവുന്നതാണ്."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ആപ്പ് ലഭ്യമല്ല"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല. <xliff:g id="APP_NAME_1">%2$s</xliff:g> ആണ് ഇത് മാനേജ് ചെയ്യുന്നത്."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"കൂടുതലറിയുക"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ആപ്പ് പുനഃരാംഭിക്കുക"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കണോ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"നിങ്ങളുടെ ഔദ്യോഗിക ആപ്പുകൾ, അറിയിപ്പുകൾ, ഡാറ്റ, മറ്റ് ഔദ്യോഗിക പ്രൊഫൈൽ ഫീച്ചറുകൾ എന്നിവ ഓണാക്കും"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ഓണാക്കുക"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"സ്ക്രീൻ വിഭജന മോഡ് മാറ്റുക"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്ക്രീൻ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ഉപയോഗസഹായി മെനു"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 3acdb7245b7c..cc031754b2b7 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Хувийн аппуудыг админ түр хаасан байна"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Удирдамжийн нийцлийг шалгахын тулд энд товшино уу."</string> <string name="me" msgid="6207584824693813140">"Би"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Таблетын сонголтууд"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ТВ-н сонголт"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл бүртгэлээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Устгах"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-н дэлгэц дээрх үйлчилгээг эхлүүлдэг дэвсгэр нь цаашид R хийцийн ашиглах үеийн зөвшөөрөлгүй болно. go/r-bg-fgs-restriction-г үзэж, алдааны мэдээ илгээнэ үү."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Товчлолыг асаасан үед дуун товчлуурыг 3 секунд дарснаар хүртээмжийн онцлогийг эхлүүлнэ.\n\n Одоогийн хүртээмжийн онцлог:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Онцлогийг Тохиргоо > Хүртээмж хэсэгт өөрчлөх боломжтой."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апп боломжгүй байна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> одоогоор боломжгүй байна. Үүнийг <xliff:g id="APP_NAME_1">%2$s</xliff:g>-р удирддаг."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Дэлгэрэнгүй үзэх"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Аппыг түр зогсоохоо болих"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ажлын профайлыг асаах уу?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Таны ажлын апп, мэдэгдэл, өгөгдөл болон бусад ажлын профайлын онцлогийг асаана"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Асаах"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Дэлгэц хуваахыг унтраах/асаах"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Хандалтын цэс"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index ff9f3e741c85..cd9b6fc5ee5a 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ॲडमिनद्वारे वैयक्तिक ॲप निलंबित केले गेले आहेत"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"धोरणाचे पालन तपासण्यासाठी येथे टॅप करा."</string> <string name="me" msgid="6207584824693813140">"मी"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"टॅबलेट पर्याय"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV पर्याय"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"काढा"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> कडून बॅकग्राउंडने फोरग्राउंडमध्ये सुरू केलेल्या सेवेला भविष्यातील आर बिल्डमध्ये वापर करते वेळची परवानगी नसेल. कृपया go/r-bg-fgs-restriction पहा आणि बगची तक्रार नोंदवा."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"शिफारस केलेल्या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्याने आपल्या श्रवणशक्तीची हानी होऊ शकते."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"शॉर्टकट चालू असताना, दोन्ही आवाज बटणे 3 सेकंद दाबल्याने प्रवेशयोग्यता वैशिष्ट्य सुरू होईल.\n\n वर्तमान प्रवेशयोग्यता वैशिष्ट्य:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तुम्ही सेटिंग्ज > प्रवेशयोग्यता मध्ये वैशिष्ट्य बदलू शकता."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"अॅप उपलब्ध नाही"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"अॅप उघडा"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल चालू ठेवायची?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये चालू केली जातील"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करा"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रीन टॉगल करा"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"अॅक्सेसिबिलिटी मेनू"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index e4364083751d..0a4073519b59 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Apl peribadi telah digantung oleh pentadbir"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ketik di sini untuk menyemak pematuhan dasar."</string> <string name="me" msgid="6207584824693813140">"Saya"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Pilihan tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Pilihan Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Alih keluar"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Perkhidmatan latar depan dimulakan latar belakang daripada <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan mempunyai kebenaran semasa-dalam-penggunaan dalam binaan R akan datang. Sila lihat go/r-bg-fgs-restriction dan failkan laporan pepijat."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan.\n\n Ciri kebolehaksesan semasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda boleh menukar ciri itu dalam Tetapan > Kebolehaksesan."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Apl tidak tersedia"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tidak tersedia sekarang. Ini diurus oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ketahui lebih lanjut"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Nyahjeda apl"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Hidupkan profil kerja?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Apl kerja, pemberitahuan, data dan ciri profil kerja anda yang lain akan dihidupkan"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Togol Skrin Pisah"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Kebolehaksesan"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 56f49c28b26d..9e048411b5c7 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string> <string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ကိုယ်ပိုင်အက်ပ်များကို စီမံခန့်ခွဲသူက ဆိုင်းငံ့ထားသည်"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"မူဝါဒလိုက်နာမှုကို စစ်ဆေးရန် ဤနေရာကို တို့ပါ။"</string> <string name="me" msgid="6207584824693813140">"ကျွန်ုပ်"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletဆိုင်ရာရွေးချယ်မှုများ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ရွေးချယ်စရာများ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%2$d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ဖယ်ရှားရန်"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> တွင် မှ စတင်သည့် foreground ဝန်ဆောင်မှုသည် နောက်ထွက်ရှိမည့် R စုပေါင်းစပ်ပေါင်း ပရိုဂရမ်များတွင် အသုံးပြုစဉ်အတွင်း ခွင့်ပြုချက် ရရှိမည်မဟုတ်ပါ။ go/r-bg-fgs-ကန့်သတ်ချက်များကို ကြည့်ပြီး အမှားသတင်းပို့ချက်တစ်ခု တင်သွင်းပါ။"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံအတိုးအလျှော့ခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။\n\n လက်ရှိ အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှု−\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ဝန်ဆောင်မှုကို ဆက်တင်များ > အများသုံးစွဲနိုင်မှုတွင် ပြောင်းလဲနိုင်ပါသည်။"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"အက်ပ်ကို မရရှိနိုင်ပါ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ကို လောလောဆယ် မရနိုင်ပါ။ ၎င်းကို <xliff:g id="APP_NAME_1">%2$s</xliff:g> က စီမံထားပါသည်။"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ပိုမိုလေ့လာရန်"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"အက်ပ်ကို ခဏမရပ်တော့ရန်"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"အလုပ်ပရိုဖိုင် ဖွင့်လိုသလား။"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"သင်၏ အလုပ်အက်ပ်၊ အကြောင်းကြားချက်၊ ဒေတာနှင့် အခြားအလုပ်ပရိုဖိုင် ဝန်ဆောင်မှုများကို ဖွင့်လိုက်ပါမည်"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ဖွင့်ပါ"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို နှိပ်ပါ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"အများသုံးစွဲနိုင်မှု မီနူး"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ကိုယ်ပိုင်"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"အလုပ်"</string> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index bb3d52f7b854..45ab3e552c17 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personlige apper er sperret midlertidig av en administrator"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Trykk her for å sjekke overholdelse av retningslinjer."</string> <string name="me" msgid="6207584824693813140">"Meg"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Innstillinger for nettbrettet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-alternativer"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjern"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnstjenesten fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, som ble startet i bakgrunnen, kommer ikke til å ha tillatelser mens den er i bruk i fremtidige R-delversjoner. Les go/r-bg-fgs-restriction og send inn en feilrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder.\n\n Nåværende tilgjengelighetsfunksjon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan endre funksjonen i Innstillinger > Tilgjengelighet."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgjengelig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgjengelig akkurat nå. Dette administreres av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Finn ut mer"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opphev pause for appen"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Vil du slå på jobbprofilen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappene dine samt varsler, data og andre funksjoner i jobbprofilen din blir slått på"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå delt skjerm av/på"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Tilgjengelighet-meny"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index b3d6cdecf8ed..11033a740aa1 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको अनुप्रयोग प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"व्यक्तिगत एपहरू एकजना प्रशासकले निलम्बन गरिरहनुभएको छ"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"नीति पालनाबारे जाँच गर्न यहाँ ट्याप गर्नुहोस्।"</string> <string name="me" msgid="6207584824693813140">"मलाई"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ट्याब्लेट विकल्पहरू"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV सम्बन्धी विकल्पहरू"</string> @@ -1619,8 +1617,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"हटाउनुहोस्"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> को पृष्ठभूमिबाट सुरु गरिने अग्रभूमि सेवाका भविष्यमा आउने R बिल्डहरूमा चलाउँदै गर्दा प्रयोग गर्ने अनुमतिको दिइने छैन। कृपया go/r-bg-fgs-restriction हेर्नुहोस् र कुनै बगसम्बन्धी रिपोर्ट फाइल गर्नुहोस्।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"सर्टकट सक्रिय हुँदा, भोल्युमका दुवै बटनहरूलाई ३ सेकेन्डसम्म थिची राख्नाले पहुँच सम्बन्धी कुनै सुविधा सुरु हुनेछ।\n\n हाल व्यवहारमा रहेको पहुँच सम्बन्धी सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तपाईं सेटिङहरू अन्तर्गतको पहुँच सम्बन्धी विकल्पमा गई उक्त सुविधालाई बदल्न सक्नुहुन्छ।"</string> @@ -1858,8 +1855,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"अनुप्रयोग उपलब्ध छैन"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> अहिले उपलब्ध छैन। यो <xliff:g id="APP_NAME_1">%2$s</xliff:g> द्वारा व्यवस्थित छ।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"थप जान्नुहोस्"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"एपको पज हटाउनुहोस्"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल सक्रिय गर्ने?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"तपाईंका कार्यसम्बन्धी अनुप्रयोग, सूचना, डेटा र कार्य प्रोफाइलका अन्य सुविधाहरू सक्रिय गरिने छन्"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"सक्रिय गर्नुहोस्"</string> @@ -2013,12 +2009,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रिन टगल गर्नुहोस्"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"पहुँचसम्बन्धी मेनु"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 47de950c5c7d..13f6725c82b7 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string> <string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Persoonlijke apps zijn opgeschort door een beheerder"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tik hier om beleidsnaleving te controleren."</string> <string name="me" msgid="6207584824693813140">"Ik"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletopties"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opties voor Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Verwijderen"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"De op de achtergrond gestarte voorgrondservice van <xliff:g id="PACKAGENAME">%1$s</xliff:g> heeft geen rechten tijdens gebruik in toekomstige R-builds. Ga naar go/r-bg-fgs-restriction en dien een bugrapport in."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen > Toegankelijkheid."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"App is niet beschikbaar"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nu niet beschikbaar. Dit wordt beheerd door <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Meer info"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App niet meer onderbreken"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Werkprofiel inschakelen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Je werk-apps, meldingen, gegevens en andere functies van je werkprofiel worden uitgeschakeld"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Inschakelen"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Gesplitst scherm schakelen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Toegankelijkheidsmenu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 1242188f791a..4424af7dcab0 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକୁ ଆଡମିନଙ୍କ ଦ୍ୱାରା ସାମୟିକ ଭାବରେ ବନ୍ଦ କରାଯାଇଛି"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ନୀତି ଅନୁପାଳନର ଯାଞ୍ଚ କରିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ।"</string> <string name="me" msgid="6207584824693813140">"ମୁଁ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ଟାବଲେଟ୍ର ବିକଳ୍ପ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ଟିଭିର ବିକଳ୍ପଗୁଡ଼ିକ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନ୍କୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ବାହାର କରନ୍ତୁ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ପୃଷ୍ଠଭୂମିରେ <xliff:g id="PACKAGENAME">%1$s</xliff:g>ରୁ ଆରମ୍ଭ ହୋଇଥିବା ସମ୍ମୁଖଭାଗ ସେବା ପାଇଁ ଭବିଷ୍ୟତର R ବିଲ୍ଡଗୁଡ଼ିକରେ ବ୍ୟବହାର କରାଯିବା ସମୟରେ ଅନୁମତି ସୁବିଧା ରହିବ ନାହିଁ। ଦୟାକରି go/r-bg-fgs-restriction ଦେଖନ୍ତୁ ଏବଂ ଏକ ବଗରିପୋର୍ଟ ଫାଇଲ୍ କରନ୍ତୁ।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରିବେ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ସର୍ଟକଟ୍ ଅନ୍ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ ଆରମ୍ଭ ହେବ।\n\n ସମ୍ପ୍ରତି ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ୍ୟ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ସେଟିଙ୍ଗ ଓ ଆକ୍ସେସବିଲିଟିରେ ଆପଣ ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇ ପାରିବେ।"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ଆପ୍ ଅନପଜ୍ କରନ୍ତୁ"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ଚାଲୁ କରିବେ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ଆପଣଙ୍କର କାର୍ଯ୍ୟକାରୀ ଆପ୍, ବିଜ୍ଞପ୍ତି, ଡାଟା ଓ ଅନ୍ୟ ୱର୍କ ପ୍ରୋଫାଇଲ୍ଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ଅନ୍ କରନ୍ତୁ"</string> @@ -1989,8 +1985,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ସ୍ପ୍ରେଡ୍ସିଟ୍"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ଉପସ୍ଥାପନା"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ଉପସ୍ଥାପନା"</string> - <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> - <skip /> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ଏୟାରପ୍ଲେନ୍ ମୋଡରେ ବ୍ଲୁଟୁଥ୍ ଚାଲୁ ରହିବ"</string> <string name="car_loading_profile" msgid="8219978381196748070">"ଲୋଡ୍ ହେଉଛି"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g>ଟି ଫାଇଲ୍</item> @@ -2008,13 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ଦୁଇଟି ସ୍କ୍ରିନ୍ ମଧ୍ୟରେ ଟୋଗଲ୍ କରନ୍ତୁ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ଆକ୍ସେସିବିଲିଟୀ ମେନୁ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string> - <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> - <skip /> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index b6513c399559..8c87581f9a61 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ਨਿੱਜੀ ਐਪਾਂ ਨੂੰ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮੁਅੱਤਲ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ਨੀਤੀ ਦੀ ਪਾਲਣਾ ਨੂੰ ਦੇਖਣ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ।"</string> <string name="me" msgid="6207584824693813140">"ਮੈਂ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ਟੈਬਲੈੱਟ ਵਿਕਲਪ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ਦੇ ਵਿਕਲਪ"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ਹਟਾਓ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ਤੋਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਸ਼ੁਰੂ ਕੀਤੀ ਗਈ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਲਈ ਭਵਿੱਖੀ R ਬਿਲਡ ਵਿੱਚ \'ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ \'ਤੇ ਇਜਾਜ਼ਤ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨਹੀਂ ਹੋਵੇਗੀ। ਕਿਰਪਾ ਕਰਕੇ go/r-bg-fgs-restriction ਦੇਖੋ ਅਤੇ ਬੱਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਕਰੋ।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ਕੀ ਵੌਲਿਊਮ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣਾ ਹੈ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।\n\n ਵਰਤਮਾਨ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ > ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਐਪ ਫਿਲਹਾਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਇਸਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ਹੋਰ ਜਾਣੋ"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ਐਪ ਤੋਂ ਰੋਕ ਹਟਾਓ"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"ਕੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰਨੀ ਹੈ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ਤੁਹਾਡੀਆਂ ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ, ਸੂਚਨਾਵਾਂ, ਡਾਟਾ ਅਤੇ ਹੋਰ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string> @@ -1989,8 +1985,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਸਪਰੈੱਡਸ਼ੀਟ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ਪੇਸ਼ਕਾਰੀ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਪੇਸ਼ਕਾਰੀ"</string> - <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> - <skip /> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ ਵੇਲੇ ਬਲੂਟੁੱਥ ਹਾਲੇ ਵੀ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string> <string name="car_loading_profile" msgid="8219978381196748070">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ਫ਼ਾਈਲ</item> @@ -2008,13 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ਪਹੁੰਚਯੋਗਤਾ ਮੀਨੂ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string> - <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> - <skip /> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 964c973e491f..5efbfbe36830 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -95,7 +95,7 @@ <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Stan mobilnej transmisji danych"</string> <string name="notification_channel_sms" msgid="1243384981025535724">"SMS-y"</string> <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Wiadomości poczty głosowej"</string> - <string name="notification_channel_wfc" msgid="9048240466765169038">"Połączenia przez Wi-Fi"</string> + <string name="notification_channel_wfc" msgid="9048240466765169038">"Połączenie przez Wi-Fi"</string> <string name="notification_channel_sim" msgid="5098802350325677490">"Stan karty SIM"</string> <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"Stan karty SIM – wysoki priorytet"</string> <string name="peerTtyModeFull" msgid="337553730440832160">"Drugie urządzenie zażądało trybu „TTY pełny”"</string> @@ -133,14 +133,14 @@ </string-array> <!-- no translation found for wfcSpnFormat_spn (2982505428519096311) --> <skip /> - <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string> + <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez Wi-Fi"</string> <string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen" msgid="3836827895369365298">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string> <string name="wfcSpnFormat_wlan_call" msgid="4895315549916165700">"Połączenie przez WLAN"</string> <string name="wfcSpnFormat_spn_wlan_call" msgid="255919245825481510">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez WLAN"</string> <string name="wfcSpnFormat_spn_wifi" msgid="7232899594327126970">"<xliff:g id="SPN">%s</xliff:g>, Wi-Fi"</string> <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"Połączenia przez Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string> <string name="wfcSpnFormat_spn_vowifi" msgid="6865214948822061486">"<xliff:g id="SPN">%s</xliff:g>, VoWifi"</string> - <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Połączenia przez Wi-Fi"</string> + <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Połączenie przez Wi-Fi"</string> <string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string> <string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Połączenia przez Wi-Fi"</string> <string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string> @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikacje osobiste zostały zawieszone przez administratora"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Kliknij tutaj, by sprawdzić zgodność z zasadami."</string> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcje tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcje Androida TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Usuń"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Uruchomiona w tle usługa działająca w pierwszym planie z pakietu <xliff:g id="PACKAGENAME">%1$s</xliff:g> nie będzie miała uprawnień obowiązujących podczas używania w przyszłych kompilacjach R. Zapoznaj się z ograniczeniem go/r-bg-fgs-restriction i zgłoś błąd."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Gdy skrót jest włączony, jednoczesne naciśnięcie przez trzy sekundy obu klawiszy sterowania głośnością uruchomi funkcję ułatwień dostępu.\n\nBieżąca funkcja ułatwień dostępu:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nFunkcję możesz zmienić, wybierając Ustawienia > Ułatwienia dostępu."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacja niedostępna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie jest teraz dostępna. Zarządza tym aplikacja <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Więcej informacji"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Wznów działanie aplikacji"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil służbowy?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacje do pracy, powiadomienia, dane i inne funkcje profilu do pracy zostaną włączone"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Przełącz podzielony ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu ułatwień dostępu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index a6fd0fe230ec..db4844163ba9 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Os apps pessoais foram suspensos por um administrador"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para ver a conformidade com a política."</string> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu de acessibilidade"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> - <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 81f5ced0a044..04296fe10378 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a aplicação de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"As apps pessoais foram suspensas por um administrador"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para verificar a conformidade da política."</string> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> não terá a autorização durante a utilização em compilações R futuras. Aceda a go/r-bg-fgs-restriction e envie um relatório de erros."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade.\n\n Funcionalidade de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pode alterar a funcionalidade em Definições > Acessibilidade."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"A aplicação não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicação <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível neste momento. A aplicação <xliff:g id="APP_NAME_1">%2$s</xliff:g> gere esta definição."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"As aplicações de trabalho, as notificações, os dados e outras funcionalidades do perfil de trabalho serão desativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar/desativar o ecrã dividido"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecrã de bloqueio"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de ecrã"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Acessibilidade"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index a6fd0fe230ec..db4844163ba9 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Os apps pessoais foram suspensos por um administrador"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para ver a conformidade com a política."</string> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu de acessibilidade"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> - <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index cb8d3fee32ca..030e76a2f6cf 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplicațiile personale au fost suspendate de un administrator"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Atingeți aici ca să verificați conformitatea cu politicile."</string> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opțiuni tablet PC"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opțiuni pentru Android TV"</string> @@ -1635,8 +1633,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminați"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Serviciul în prim-plan inițializat în fundal din <xliff:g id="PACKAGENAME">%1$s</xliff:g> nu va avea permisiunea în timpul utilizării în versiunile R viitoare. Consultați go/r-bg-fgs-restriction și trimiteți un raport de eroare."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de 3 secunde, veți lansa o funcție de accesibilitate.\n\n Funcția actuală de accesibilitate:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puteți schimba funcția în Setări > Accesibilitate."</string> @@ -1884,8 +1881,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplicația nu este disponibilă"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Momentan, aplicația <xliff:g id="APP_NAME_0">%1$s</xliff:g> nu este disponibilă. Aceasta este gestionată de <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Aflați mai multe"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulați întreruperea aplicației"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Activați profilul de serviciu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Se vor activa aplicațiile dvs. de serviciu, notificările, datele și alte funcții ale profilului de serviciu"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activați"</string> @@ -2041,12 +2037,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activați ecranul împărțit"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meniul Accesibilitate"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 4821c7f9d175..94029f51c0c0 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Личные приложения временно заблокированы администратором"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Нажмите здесь, чтобы проверить их на соответствие правилам."</string> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Настройки планшетного ПК"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Настройки Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Удалить"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Службы из пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, переведенные из фонового режима в активный, не будут получать разрешение while-in-use в будущих сборках на языке R. Перейдите на страницу go/r-bg-fgs-restriction и отправьте отчет об ошибке."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Использовать быстрое включение?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте три секунды обе кнопки регулировки громкости.\n\nТекущая функция специальных возможностей:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nВы можете изменить ее в разделе \"Настройки > Специальные возможности\"."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Приложение недоступно"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Приложение \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" недоступно. Его работу ограничивает приложение \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Подробнее"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Возобновить работу приложения"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Включить рабочий профиль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Будут включены корпоративные приложения, уведомления, данные и другие функции рабочего профиля."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Включить"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Включить или выключить разделение экрана"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню специальных возможностей"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index df14036c1a07..73cf01890108 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string> <string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"පුද්ගලික යෙදුම් පරිපාලකයෙකු විසින් අත්හිටුවා ඇත"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ප්රතිපත්ති අනුකූලතාව පරීක්ෂා කිරීමට මෙහි තට්ටු කරන්න."</string> <string name="me" msgid="6207584824693813140">"මම"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ටැබ්ලට විකල්ප"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV විකල්ප"</string> @@ -1615,8 +1613,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ඉවත් කරන්න"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> වෙතින් පසුබිම ආරම්භ කරන ලද පෙරබිම් සේවාව අනාගත R තැනුම්වලදී භාවිතයේ අවසරය නැත. කරුණාකර go/r-bg-fgs-අවහිරතාව බලා දෝෂ වාර්තාවක් ගොනු කරන්න."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ප්රවේශ්යතා කෙටිමඟ භාවිතා කරන්නද?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"කෙටිමඟ සක්රිය විට, හඬ බොත්තම් දෙකම තත්පර 3ක් අල්ලාගෙන සිටීමෙන් ප්රවේශ්යත අංගයක් ඇරඹේ.\n\n වත්මන් ප්රවේශ්යතා අංගය:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n සැකසීම් > ප්රවේශ්යතාව තුළ ඔබට අංගය වෙනස් කළ හැක."</string> @@ -1854,8 +1851,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"යෙදුම නොතිබේ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> මේ අවස්ථාවේදී ලබා ගත නොහැකිය. මෙය <xliff:g id="APP_NAME_1">%2$s</xliff:g> මගින් කළමනාකරණය කෙරේ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"තව දැන ගන්න"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"යෙදුම විරාම කිරීම ඉවත් කරන්න"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"කාර්යාල පැතිකඩ ක්රියාත්මක කරන්නද?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ඔබගේ වැඩ යෙදුම්, දැනුම්දීම්, දත්ත සහ වෙනත් කාර්යාල පැතිකඩ විශේෂාංග ක්රියාත්මක කරනු ඇත"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ක්රියාත්මක කරන්න"</string> @@ -2009,12 +2005,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"බෙදුම් තිරය ටොගල කරන්න"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ප්රවේශ්යතා මෙනුව"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index b0dc5f3cd342..b86fc4696a01 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osobné aplikácie boli pozastavené správcom"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Klepnutím tu skontrolujte súlad s pravidlami."</string> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zariadenia Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odstrániť"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba na popredí spustená na pozadí z balíka <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebude mať v budúcich zostavách R povolenie Počas používania. Prejdite na go/r-bg-fgs-restriction a odošlite hlásenie chyby."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti.\n\n Aktuálna funkcia dostupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciu môžete zmeniť v časti Nastavenia > Dostupnosť."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikácia nie je k dispozícii"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie je momentálne k dispozícii. Spravuje to aplikácia <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ďalšie informácie"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Znova spustiť aplikáciu"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Zapnúť pracovný profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Pracovné aplikácie, upozornenia, dáta a ďalšie funkcie pracovného profilu sa zapnú"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Prepnúť rozdelenú obrazovku"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Ponuka Dostupnosť"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index bdd5925d8a3e..bc2bc3acb7db 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osebne aplikacije je onemogočil skrbnik"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dotaknite se tukaj, da preverite skladnost s pravilniki."</string> <string name="me" msgid="6207584824693813140">"Jaz"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabličnega računalnika"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti naprave Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odstrani"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"V prihodnjih različicah R storitev v ospredju z zagonom iz ozadja iz paketa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne bo imela dovoljenja med uporabo aplikacije. Oglejte si go/r-bg-fgs-restriction in pošljite poročilo o napakah."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami.\n\n Trenutna funkcija za ljudi s posebnimi potrebami:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkcijo lahko spremenite v »Nastavitve > Funkcije za ljudi s posebnimi potrebami«."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija ni na voljo"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno ni na voljo. To upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Več o tem"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekliči začasno zaustavitev aplikacije"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Želite vklopiti delovni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vklopili boste svoje delovne aplikacije, obvestila, podatke in druge funkcije delovnega profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Vklop"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Preklop razdeljenega zaslona"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni s funkcijami za ljudi s posebnimi potrebami"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index fd8dda060448..a35328879f29 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikacionet personale janë pezulluar nga një administrator"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Trokit këtu për të kontrolluar përputhshmërinë me politikën."</string> <string name="me" msgid="6207584824693813140">"Unë"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsionet e tabletit"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsionet e Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Hiq"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Shërbimi në plan të parë i nisur në sfond nga <xliff:g id="PACKAGENAME">%1$s</xliff:g> nuk do të ketë lejen e nevojshme gjatë përdorimit në ndërtimet e ardhshme R. Shiko go/r-bg-fgs-restriction dhe dërgo një raport të defekteve në kod."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie.\n\n Funksioni aktual i qasshmërisë:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Mund ta ndryshosh funksionin te Cilësimet > Qasshmëria."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacioni nuk ofrohet"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> nuk ofrohet në këtë moment. Kjo menaxhohet nga <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Mëso më shumë"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulo pauzën për aplikacionin"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Të aktivizohet profili i punës?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacionet e punës, njoftimet, të dhënat e tua dhe funksionet e tjera të profilit të punës do të aktivizohen"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Kalo tek ekrani i ndarë"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menyja e qasshmërisë"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Puna"</string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index d82faa66ed12..8ee644ad2e4f 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -196,10 +196,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Администратор је суспендовао личне апликације"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Додирните овде да бисте проверили усклађеност са смерницама."</string> <string name="me" msgid="6207584824693813140">"Ја"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опције за таблет"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опције Android TV-а"</string> @@ -1635,8 +1633,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде/и."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Уклони"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услуга у првом плану са <xliff:g id="PACKAGENAME">%1$s</xliff:g> која је покренута у позадини неће имати дозволу током коришћења у будућим R верзијама. Посетите go/r-bg-fgs-restriction и пошаљите извештај о грешци."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Желите ли да користите пречицу за приступачност?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности.\n\n Актуелна функција приступачности:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцију у одељку Подешавања > Приступачност."</string> @@ -1884,8 +1881,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апликација није доступна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Апликација <xliff:g id="APP_NAME_0">%1$s</xliff:g> тренутно није доступна. <xliff:g id="APP_NAME_1">%2$s</xliff:g> управља доступношћу."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Сазнајте више"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Опозови паузирање апликације"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо профил за Work?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције профила за Work"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string> @@ -2041,12 +2037,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Укључите/искључите подељени екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Мени Приступачност"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 9c7e1e5ecc4b..577933e6a296 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administratören har stängt av privata appar"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tryck här för att kontrollera att policyn följs."</string> <string name="me" msgid="6207584824693813140">"Jag"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Alternativ för surfplattan"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Alternativ för Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ta bort"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Förgrundstjänsten från <xliff:g id="PACKAGENAME">%1$s</xliff:g> som startades i bakgrunden får inte behörighet som gäller vid användning i framtida R-versioner. Besök go/r-bg-fgs-restriction och skicka en felrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder.\n\n Aktuell tillgänglighetsfunktion:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan ändra funktionen i Inställningar > Tillgänglighet."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen är inte tillgänglig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> är inte tillgänglig just nu. Detta hanteras av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Läs mer"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Återuppta app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Vill du aktivera jobbprofilen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappar, aviseringar, data och andra funktioner i jobbprofilen aktiveras"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktivera och inaktivera delad skärm"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmdump"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Tillgänglighetsmenyn"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index f53efe068aec..a6ee3667b3c1 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Programu za binafsi zimesimamishwa na msimamizi"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Gusa hapa ili uangalie utii wa sera."</string> <string name="me" msgid="6207584824693813140">"Mimi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Chaguo za kompyuta ndogo"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Chaguo za Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ondoa"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Huduma ya programu inayotumika iliyoanzishwa chinichini kwenye <xliff:g id="PACKAGENAME">%1$s</xliff:g> haitakuwa na ruhusa inapotumika katika miundo ijayo ya R. Tafadhali angalia go/r-bg-fgs-restriction na uwasilishe ripoti ya hitilafu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha ufikivu.\n\n Kipengele cha ufikivu kilichopo kwa sasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio > Zana za ufikivu."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Programu haipatikani"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> haipatikani kwa sasa. Inasimamiwa na <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Pata maelezo zaidi"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Acha kusimamisha programu"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ungependa kuwasha wasifu wa kazini?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini, arifa na vipengele vingine vya wasifu wa kazini"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Geuza Skrini Iliyogawanywa"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menyu ya Ufikivu"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index c7c4ea3c6a5b..a56465fcd8ac 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string> <string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"தனிப்பட்ட ஆப்ஸை நிர்வாகி ஒருவர் இடைநிறுத்தியுள்ளார்"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"கொள்கை இணக்கத்தைச் சரிபார்ப்பதற்கு இங்கே தட்டவும்."</string> <string name="me" msgid="6207584824693813140">"நான்"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"டேப்லெட் விருப்பங்கள்"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV விருப்பத்தேர்வுகள்"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%2$d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"அகற்று"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> இல் இருந்து பின்னணியில் தொடங்கப்பட்ட முன்புலச் சேவைக்கு, வரவுள்ள R பதிப்புகளில் உபயோகத்தின்போது மட்டுமான அனுமதி இருக்காது. go/r-bg-fgs-restriction என்பதைப் பார்த்து பிழை அறிக்கை ஒன்றைச் சமர்ப்பிக்கவும்."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ஷார்ட்கட் இயக்கத்தில் இருந்தால், இரண்டு ஒலியளவு பொத்தான்களையும் 3 வினாடிகள் அழுத்தி, அணுகல்தன்மை அம்சத்தை இயக்கலாம்.\n\n தற்போதைய அணுகல்தன்மை அம்சம்:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n அமைப்புகள் > அணுகல்தன்மை என்பதற்குச் சென்று, அம்சத்தை மாற்றலாம்."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ஆப்ஸை உபயோகிக்க இயலாது"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"இப்போது <xliff:g id="APP_NAME_0">%1$s</xliff:g> ஆப்ஸை உபயோகிக்க இயலாது. இதை <xliff:g id="APP_NAME_1">%2$s</xliff:g> நிர்வகிக்கிறது."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"மேலும் அறிக"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ஆப்ஸ் இயக்கு"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"பணிச் சுயவிவரத்தை ஆன் செய்யவா?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"பணி ஆப்ஸ், அறிவிப்புகள், தரவு மற்றும் பிற பணிச் சுயவிவர அம்சங்கள் ஆன் செய்யப்படும்"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"இயக்கு"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"திரைப் பிரிப்பை நிலைமாற்று"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"அணுகல்தன்மை மெனு"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"தனிப்பட்ட சுயவிவரம்"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"பணிச் சுயவிவரம்"</string> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 9c77ccd01b92..7a0aece84500 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string> <string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"అడ్మిన్ ద్వారా వ్యక్తిగత యాప్లు సస్పెండ్ చేయబడ్డాయి"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"పాలసీ పాటించబడుతోందో లేదో తనిఖీ చేయడానికి ఇక్కడ ట్యాప్ చేయండి."</string> <string name="me" msgid="6207584824693813140">"నేను"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"టాబ్లెట్ ఎంపికలు"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ఎంపికలు"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"తీసివేయి"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> నుండి, బ్యాక్గ్రౌండ్లో ప్రారంభమైన ఫోర్ గ్రౌండ్ సేవకు భవిష్యత్తు R బిల్డ్స్లో \'ఉపయోగంలో వున్నప్పుడు\' అనుమతి ఉండదు. దయచేసి go/r-bg-fgs-restrictionను చూసి బగ్ నివేదికను ఫైల్ చేయండి."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్కట్ను ఉపయోగించాలా?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"షార్ట్కట్ ఆన్లో ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కితే యాక్సెస్ సామర్థ్య ఫీచర్ ప్రారంభం అవుతుంది.\n\n ప్రస్తుత యాక్సెస్ సామర్థ్య ఫీచర్:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n సెట్టింగ్లు > యాక్సెస్ సామర్థ్యంలో మీరు ఫీచర్ను మార్చవచ్చు."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"యాప్ అందుబాటులో లేదు"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు. ఇది <xliff:g id="APP_NAME_1">%2$s</xliff:g> ద్వారా నిర్వహించబడుతుంది."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"మరింత తెలుసుకోండి"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"యాప్పై వున్న పాజ్ను తొలగించండి"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"కార్యాలయ ప్రొఫైల్ని ఆన్ చేయాలా?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"మీ కార్యాలయ యాప్లు, నోటిఫికేషన్లు, డేటా మరియు ఇతర కార్యాలయ ప్రొఫైల్ ఫీచర్లు ఆన్ చేయబడతాయి"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ఆన్ చేయి"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"స్క్రీన్ విభజనను టోగుల్ చేయి"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"యాక్సెసిబిలిటీ మెను"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index efff25bf74c8..98f2d8880b8a 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ผู้ดูแลระบบได้ระงับแอปส่วนตัวไว้"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"แตะที่นี่เพื่อตรวจสอบการปฏิบัติตามข้อกำหนดของนโยบาย"</string> <string name="me" msgid="6207584824693813140">"ฉัน"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ตัวเลือกของแท็บเล็ต"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ตัวเลือกของ Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ลบ"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"บริการที่ทำงานอยู่เบื้องหน้าซึ่งเริ่มขึ้นในเบื้องหลังจาก <xliff:g id="PACKAGENAME">%1$s</xliff:g> จะไม่มีสิทธิ์ขณะใช้งานใน R บิลด์ต่อๆ ไป โปรดดู go/r-bg-fgs-restriction และส่งรายงานข้อบกพร่อง"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ใช้ทางลัดการช่วยเหลือพิเศษไหม"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มเป็นเวลา 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ\n\n ฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n คุณสามารถเปลี่ยนฟีเจอร์ในการตั้งค่า > การช่วยเหลือพิเศษ"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"แอปไม่พร้อมใช้งาน"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"เปิด <xliff:g id="APP_NAME_0">%1$s</xliff:g> ไม่ได้ในขณะนี้ แอปนี้จัดการโดย <xliff:g id="APP_NAME_1">%2$s</xliff:g>"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ดูข้อมูลเพิ่มเติม"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ยกเลิกการหยุดแอปชั่วคราว"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"เปิดโปรไฟล์งานไหม"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ระบบจะเปิดแอปงาน การแจ้งเตือน ข้อมูล และฟีเจอร์อื่นๆ ในโปรไฟล์งาน"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"เปิด"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"เปิด/ปิดการแบ่งหน้าจอ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"เมนูการช่วยเหลือพิเศษ"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 7cfa7b02ebaa..c38a6d54cdbd 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Sinuspinde ng isang admin ang mga personal na app"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Mag-tap dito para matingnan ang pagsunod sa patakaran."</string> <string name="me" msgid="6207584824693813140">"Ako"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Mga pagpipilian sa tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Mga opsyon sa Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Alisin"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ang sinimulan sa background na serbisyo sa foreground mula sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ay hindi magkakaroon ng pahintulot habang ginagamit sa mga R build sa hinaharap. Pakipuntahan ang go/r-bg-fgs-restriction at maghain ng bugreport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting > Pagiging Accessible."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Hindi available ang app"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Hindi available ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa ngayon. Pinamamahalaan ito ng <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Matuto pa"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"I-unpause ang app"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"I-on ang profile sa trabaho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Mao-on ang iyong mga app sa trabaho, notification, data, at iba pang feature sa profile sa trabaho"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"I-toggle ang Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu ng Accessibility"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index b47eb4bb025c..5e0930947afb 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Kişisel uygulamalar bir yönetici tarafından askıya alındı"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Politika uyumluluğunu kontrol etmek için buraya dokunun."</string> <string name="me" msgid="6207584824693813140">"Ben"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet seçenekleri"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçenekleri"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Kaldır"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> paketinden ön plan hizmetini başlatan arka plan, sonraki R derlemelerinde kullanım sırasında iznine sahip olmayacak. Lütfen go/r-bg-fgs-restriction sayfasına bakıp hata raporu girin."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kısayol açık olduğunda, ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır.\n\n Geçerli erişilebilirlik özelliği:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Özelliği, Ayarlar > Erişilebilirlik seçeneğinden değiştirebilirsiniz."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Uygulama kullanılamıyor"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulaması şu anda kullanılamıyor. Uygulamanın kullanım durumu <xliff:g id="APP_NAME_1">%2$s</xliff:g> tarafından yönetiliyor."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Daha fazla bilgi"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Uygulamanın duraklatmasını kaldır"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"İş profili açılsın mı?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"İş uygulamalarınız, bildirimleriniz, verileriniz ve diğer iş profili özellikleriniz açılacak"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekranı aç/kapat"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Erişilebilirlik Menüsü"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 22aa199d9964..1096f97e3c98 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -198,10 +198,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Особисті додатки заблоковано адміністратором"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Натисніть тут, щоб перевірити відповідність правилам."</string> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Парам. пристрою"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опції Android TV"</string> @@ -1657,8 +1655,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Вилучити"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Активний сервіс пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, запущений у фоновому режимі, не матиме дозволу \"Коли додаток використовується\" в майбутніх складаннях R. Перегляньте go/r-bg-fgs-restriction і надішліть звіт про помилки."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Використовувати швидке ввімкнення?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Коли ярлик увімкнено, після натискання обох клавіш гучності й утримування їх протягом 3 секунд увімкнеться функція спеціальних можливостей.\n\n Поточна функція спеціальних можливостей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Цю функцію можна змінити в меню \"Налаштування\" > \"Спеціальні можливості\"."</string> @@ -1916,8 +1913,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Додаток недоступний"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> зараз недоступний. Керує додаток <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Докладніше"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Відновити доступ до додатка"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Увімкнути робочий профіль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Додатки, сповіщення, дані й інші функції робочого профілю буде ввімкнено"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Увімкнути"</string> @@ -2075,12 +2071,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Розділити екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню спеціальних можливостей"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index a88d6c504964..4c331916bb57 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string> <string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ایک منتظم کے ذریعہ ذاتی ایپس معطل کر دی گئی ہیں"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"پالیسی کی تعمیل کو چیک کرنے کے ليے یہاں تھپتھپائیں۔"</string> <string name="me" msgid="6207584824693813140">"میں"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ٹیبلیٹ کے اختیارات"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV اختیارات"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ہٹائیں"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"پس منظر <xliff:g id="PACKAGENAME">%1$s</xliff:g> سے شروع کی گئی پیش منظر کی سروس کو مستقبل کے R بلڈز میں استعمال کے دوران اجازت نہیں ہوگی۔ براہ کرم go/r-bg-fgs-restriction دیکھیں اور بگ رپورٹ دائر کریں۔"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ایکسیسبیلٹی شارٹ کٹ استعمال کریں؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔\n\n موجودہ ایکسیسبیلٹی خصوصیت:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n آپ خصوصیت کو ترتیبات > ایکسیسبیلٹی میں جا کر تبدیل کر سکتے ہیں۔"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"ایپ دستیاب نہیں ہے"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔ یہ <xliff:g id="APP_NAME_1">%2$s</xliff:g> کے زیر انتظام ہے۔"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"مزید جانیں"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ایپ کو غیر موقوف کریں"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"دفتری پروفائل آن کریں؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"آپ کی دفتری ایپس، اطلاعات، ڈیٹا اور دفتری پروفائل کی دیگر خصوصیات آن کر دی جائیں گی"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"آن کریں"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"اسپلٹ اسکرین ٹوگل کریں"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ایکسیسبیلٹی مینو"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index a08b1788c5d6..23873b5f2b4f 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Shaxsiy ilovalar administrator tomonidan faolsizlantirildi"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Siyosatga muvofiqligini tekshirish uchun shu yerga bosing."</string> <string name="me" msgid="6207584824693813140">"Men"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planshet sozlamalari"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV parametrlari"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Olib tashlash"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonda faol <xliff:g id="PACKAGENAME">%1$s</xliff:g> xizmatini ishga tushirish uchun kelgusi R nashrlarida ishlatilayotganda ruxsat berish imkoniyati boʻlmaydi. go/r-bg-fgs-restriction sahifasiga kiring va xatolik hisobotini yuboring."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\n Joriy maxsus imkoniyatlar funksiyasi:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bu funksiyani Sozlamalar > Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Ilova ishlamayapti"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ishlamayapti. Uning ishlashini <xliff:g id="APP_NAME_1">%2$s</xliff:g> cheklamoqda."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Batafsil"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Ilovani ishga tushirish"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Ishchi profil yoqilsinmi?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ishchi ilovalar, bildirishnomalar, ma’lumotlar va boshqa ishchi profil imkoniyatlari yoqiladi"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ekranni ikkiga ajratish tugmasi"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Maxsus imkoniyatlar menyusi"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Shaxsiy"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Ish"</string> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index db55613dce7e..1ed30d7db57e 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Các ứng dụng cá nhân đã bị một quản trị viên tạm ngưng"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Nhấn vào đây để kiểm tra tính tuân thủ đối với chính sách."</string> <string name="me" msgid="6207584824693813140">"Tôi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tùy chọn máy tính bảng"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Tùy chọn dành cho Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Xóa"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Dịch vụ trên nền trước đã bắt đầu ở nền từ <xliff:g id="PACKAGENAME">%1$s</xliff:g> sẽ không có quyền khi đang sử dụng trong các bản dựng R trong tương lai. Vui lòng xem go/r-bg-fgs-restriction và gửi báo cáo lỗi."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Khi phím tắt được bật, nhấn cả hai nút âm lượng trong 3 giây sẽ bắt đầu một tính năng trợ năng.\n\n Tính năng trợ năng hiện tại:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bạn có thể thay đổi tính năng trong Cài đặt > Trợ năng."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Ứng dụng không sử dụng được"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hiện không sử dụng được. Chính sách này do <xliff:g id="APP_NAME_1">%2$s</xliff:g> quản lý."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Tìm hiểu thêm"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Mở lại ứng dụng"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Bạn muốn bật hồ sơ công việc?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ứng dụng công việc, thông báo, dữ liệu và các tính năng khác của hồ sơ công việc sẽ được bật"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bật/tắt chế độ chia đôi màn hình"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Trình đơn Hỗ trợ tiếp cận"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 08d232683c57..7671063821d0 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string> <string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理员已暂停个人应用"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"点按此处即可检查政策合规性。"</string> <string name="me" msgid="6207584824693813140">"我"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板电脑选项"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 选项"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"删除"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"在未来的 R 版本中,在后台启动的 <xliff:g id="PACKAGENAME">%1$s</xliff:g> 中的前台服务将不具有仅在使用时授予的权限。请访问 go/r-bg-fgs-restriction 并提交错误报告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用无障碍快捷方式吗?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"开启快捷方式后,同时按下两个音量按钮 3 秒钟即可启动所设定的无障碍功能。\n\n当前设定的无障碍功能:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如需更改设定的功能,请依次转到“设置”>“无障碍”。"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"应用无法使用"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>目前无法使用。该应用是由<xliff:g id="APP_NAME_1">%2$s</xliff:g>所管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"了解详情"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暂停应用"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"要开启工作资料吗?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"您的工作应用、通知、数据及其他工作资料功能将会开启"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"开启"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"开启/关闭分屏"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"无障碍功能菜单"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index ea106c6c2a78..89bea07ae1a7 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理員已停用個人應用程式"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"輕按這裡查看應用程式是否符合政策要求。"</string> <string name="me" msgid="6207584824693813140">"我本人"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"移除"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"從「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」啟動前景服務的背景將不會在未來的 R 版本中提供「僅在使用此應用程式時允許」權限。請參閱 go/r-bg-fgs-restriction,提交錯誤報告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙功能快速鍵嗎?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"快速鍵開啟後,同時按住音量按鈕 3 秒,無障礙功能便會啟用。\n\n目前的無障礙功能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如要變更功能,請前往「設定」>「無障礙功能」。"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"目前無法使用此應用程式"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用 <xliff:g id="APP_NAME_0">%1$s</xliff:g>。此應用程式是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暫停應用程式"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作設定檔嗎?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟您的工作應用程式、通知、資料和其他工作設定檔功能"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割螢幕"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"無障礙功能選單"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 70651816bfbd..c95ae37602a0 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理員已將個人應用程式設為暫停使用"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"輕觸這裡即可查看政策違規問題。"</string> <string name="me" msgid="6207584824693813140">"我"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求你透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"移除"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"來自「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」的背景啟動前景服務不會具備未來 R 版本的使用狀態權限。請前往 go/r-bg-fgs-restriction 並提交錯誤報告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使你的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙捷徑嗎?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"啟用捷徑功能後,只要同時按下兩個音量鍵 3 秒,就能啟動無障礙功能。\n\n 目前設定的無障礙功能為:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n 如要變更設定的功能,請依序輕觸 [設定] > [無障礙設定]。"</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"應用程式目前無法使用"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」。這項設定是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暫停應用程式"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作資料夾嗎?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟你的辦公應用程式、通知、資料和其他工作資料夾功能"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割畫面模式"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"無障礙選單"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 1cb67e162da7..0cd669bb07a7 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -194,10 +194,8 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string> - <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> - <skip /> - <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> - <skip /> + <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Izinhlelo zokusebenza zimiswe okwesikhashana ngumlawuli"</string> + <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Thepha lapha ukuze uhlole ukuthobelana kwenqubomgomo."</string> <string name="me" msgid="6207584824693813140">"Mina"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Okukhethwa kukho kwethebhulethi"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Izinketho ze-Android TV"</string> @@ -1613,8 +1611,7 @@ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> amasekhondi."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Susa"</string> - <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) --> - <skip /> + <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ingemuva eqalise isevisi yasemuva kusuka ku-<xliff:g id="PACKAGENAME">%1$s</xliff:g> ngeke ithole imvume yokusebenzisa yesikhathi ekwakheni kwe-R ezayo. Sicela ubone i-go/r-bg-fgs-restriction bese ufayele umbiko wesiphazamiso."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Uma kuvulwe isinqamuleli, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqala isici sokufinyelela.\n\n Isici samanje sokufinyelela:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Ungashintsha isici kuzilungiselelo > Ukufinyelela."</string> @@ -1852,8 +1849,7 @@ <string name="app_suspended_title" msgid="888873445010322650">"Uhlelo lokusebenza alutholakali"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> ayitholakali okwamanje. Lokhu kuphethwe i-<xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Funda kabanzi"</string> - <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> - <skip /> + <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Susa ukuphumuza uhlelo lokusebenza"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"Vula iphrofayela yomsebenzi?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Izinhlelo zakho zokusebenza zomsebenzi, izaziso, idatha, nezinye izici zephrofayela yomsebenzi kuzovulwa"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string> @@ -2007,12 +2003,9 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Guqula ukuhlukanisa isikrini"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string> - <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> - <skip /> + <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Imenyu yokufinyeleleka"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> - <!-- no translation found for resolver_personal_tab (2051260504014442073) --> - <skip /> - <!-- no translation found for resolver_work_tab (2690019516263167035) --> - <skip /> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Okomuntu siqu"</string> + <string name="resolver_work_tab" msgid="2690019516263167035">"Umsebenzi"</string> </resources> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index cfed805d5d88..059bc443a609 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1781,8 +1781,11 @@ <attr name="crossProfile" format="boolean" /> </declare-styleable> - <!-- The <code>feature</code> tag declares a feature. A feature is a part of an app. E.g. - photo sharing app might include a direct messaging component. + <!-- The <code>feature</code> tag declares a feature. A feature is a logical part of an app. + E.g. photo sharing app might include a direct messaging component. To tag certain code as + belonging to a feature, use a context created via + {@link android.content.Context#createFeatureContext(String)} for any interaction with the + system. <p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 21128e33b6e5..21d1d3cf9c89 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1266,6 +1266,7 @@ <java-symbol type="array" name="vendor_disallowed_apps_managed_profile" /> <java-symbol type="array" name="vendor_disallowed_apps_managed_device" /> <java-symbol type="array" name="cross_profile_apps" /> + <java-symbol type="array" name="vendor_cross_profile_apps" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="default_lock_wallpaper" /> diff --git a/core/res/res/values/vendor_cross_profile_apps.xml b/core/res/res/values/vendor_cross_profile_apps.xml new file mode 100644 index 000000000000..32839cd17e1d --- /dev/null +++ b/core/res/res/values/vendor_cross_profile_apps.xml @@ -0,0 +1,24 @@ +<?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. + --> +<resources> + <!-- + A collection of apps that have been pre-approved for cross-profile communication. + These will not require admin consent, but will still require user consent during provisioning. + --> + <string-array translatable="false" name="vendor_cross_profile_apps"> + </string-array> +</resources> diff --git a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java index 09bbe37bf292..a052543c6446 100644 --- a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java +++ b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java @@ -24,10 +24,10 @@ import org.junit.Test; public class ChangeReporterTest { @Test public void testStatsLogOnce() { - ChangeReporter reporter = new ChangeReporter(0); + ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE); int myUid = 1022, otherUid = 1023; long myChangeId = 500L, otherChangeId = 600L; - int myState = 1, otherState = 2; + int myState = ChangeReporter.STATE_ENABLED, otherState = ChangeReporter.STATE_DISABLED; assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState)); reporter.reportChange(myUid, myChangeId, myState); @@ -42,10 +42,10 @@ public class ChangeReporterTest { @Test public void testStatsLogAfterReset() { - ChangeReporter reporter = new ChangeReporter(0); + ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE); int myUid = 1022; long myChangeId = 500L; - int myState = 1; + int myState = ChangeReporter.STATE_ENABLED; assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState)); reporter.reportChange(myUid, myChangeId, myState); @@ -60,10 +60,10 @@ public class ChangeReporterTest { @Test public void testDebugLogOnce() { - ChangeReporter reporter = new ChangeReporter(0); + ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE); int myUid = 1022, otherUid = 1023; long myChangeId = 500L, otherChangeId = 600L; - int myState = 1, otherState = 2; + int myState = ChangeReporter.STATE_ENABLED, otherState = ChangeReporter.STATE_DISABLED; assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState)); reporter.reportChange(myUid, myChangeId, myState); @@ -78,10 +78,10 @@ public class ChangeReporterTest { @Test public void testDebugLogAfterReset() { - ChangeReporter reporter = new ChangeReporter(0); + ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE); int myUid = 1022; long myChangeId = 500L; - int myState = 1; + int myState = ChangeReporter.STATE_ENABLED; assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState)); reporter.reportChange(myUid, myChangeId, myState); @@ -96,10 +96,10 @@ public class ChangeReporterTest { @Test public void testDebugLogWithLogAll() { - ChangeReporter reporter = new ChangeReporter(0); + ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE); int myUid = 1022; long myChangeId = 500L; - int myState = 1; + int myState = ChangeReporter.STATE_ENABLED; assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState)); reporter.reportChange(myUid, myChangeId, myState); diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java index ba29a97b55ab..d17b63597a21 100644 --- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java @@ -27,17 +27,17 @@ import android.os.TimestampedValue; import org.junit.Test; public class PhoneTimeSuggestionTest { - private static final int PHONE_ID = 99999; + private static final int SLOT_INDEX = 99999; @Test public void testEquals() { - PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(PHONE_ID); + PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(SLOT_INDEX); { PhoneTimeSuggestion one = builder1.build(); assertEquals(one, one); } - PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(PHONE_ID); + PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(SLOT_INDEX); { PhoneTimeSuggestion one = builder1.build(); PhoneTimeSuggestion two = builder2.build(); @@ -59,7 +59,7 @@ public class PhoneTimeSuggestionTest { assertEquals(two, one); } - PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(PHONE_ID + 1); + PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(SLOT_INDEX + 1); builder3.setUtcTime(new TimestampedValue<>(1111L, 2222L)); { PhoneTimeSuggestion one = builder1.build(); @@ -80,7 +80,7 @@ public class PhoneTimeSuggestionTest { @Test public void testParcelable() { - PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(PHONE_ID); + PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(SLOT_INDEX); assertRoundTripParcelable(builder.build()); builder.setUtcTime(new TimestampedValue<>(1111L, 2222L)); diff --git a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java index 0108a0bbab47..384dbf9fab07 100644 --- a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java +++ b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java @@ -26,17 +26,17 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; public class PhoneTimeZoneSuggestionTest { - private static final int PHONE_ID = 99999; + private static final int SLOT_INDEX = 99999; @Test public void testEquals() { - PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID); + PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX); { PhoneTimeZoneSuggestion one = builder1.build(); assertEquals(one, one); } - PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID); + PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX); { PhoneTimeZoneSuggestion one = builder1.build(); PhoneTimeZoneSuggestion two = builder2.build(); @@ -45,7 +45,7 @@ public class PhoneTimeZoneSuggestionTest { } PhoneTimeZoneSuggestion.Builder builder3 = - new PhoneTimeZoneSuggestion.Builder(PHONE_ID + 1); + new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX + 1); { PhoneTimeZoneSuggestion one = builder1.build(); PhoneTimeZoneSuggestion three = builder3.build(); @@ -120,7 +120,7 @@ public class PhoneTimeZoneSuggestionTest { @Test(expected = RuntimeException.class) public void testBuilderValidates_emptyZone_badMatchType() { - PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID); + PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX); // No zone ID, so match type should be left unset. builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET); builder.build(); @@ -128,7 +128,7 @@ public class PhoneTimeZoneSuggestionTest { @Test(expected = RuntimeException.class) public void testBuilderValidates_zoneSet_badMatchType() { - PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID); + PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX); builder.setZoneId("Europe/London"); builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE); builder.build(); @@ -136,7 +136,7 @@ public class PhoneTimeZoneSuggestionTest { @Test public void testParcelable() { - PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID); + PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX); assertRoundTripParcelable(builder.build()); builder.setZoneId("Europe/London"); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java index 355601ca05ed..fbe16f2c39d1 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java @@ -37,12 +37,13 @@ import android.content.pm.PackageManager; import android.os.BatteryStats; import android.os.Process; import android.text.format.DateUtils; -import android.util.StatsLog; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.FrameworkStatsLog; + import junit.framework.TestCase; import org.junit.Before; @@ -262,31 +263,31 @@ public class BatteryStatsHelperTest extends TestCase { @Test public void testDrainTypesSyncedWithProto() { assertEquals(BatterySipper.DrainType.AMBIENT_DISPLAY.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__AMBIENT_DISPLAY); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__AMBIENT_DISPLAY); // AtomsProto has no "APP" assertEquals(BatterySipper.DrainType.BLUETOOTH.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__BLUETOOTH); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__BLUETOOTH); assertEquals(BatterySipper.DrainType.CAMERA.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CAMERA); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CAMERA); assertEquals(BatterySipper.DrainType.CELL.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CELL); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CELL); assertEquals(BatterySipper.DrainType.FLASHLIGHT.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__FLASHLIGHT); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__FLASHLIGHT); assertEquals(BatterySipper.DrainType.IDLE.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__IDLE); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__IDLE); assertEquals(BatterySipper.DrainType.MEMORY.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__MEMORY); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__MEMORY); assertEquals(BatterySipper.DrainType.OVERCOUNTED.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__OVERCOUNTED); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__OVERCOUNTED); assertEquals(BatterySipper.DrainType.PHONE.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__PHONE); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__PHONE); assertEquals(BatterySipper.DrainType.SCREEN.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__SCREEN); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__SCREEN); assertEquals(BatterySipper.DrainType.UNACCOUNTED.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__UNACCOUNTED); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__UNACCOUNTED); // AtomsProto has no "USER" assertEquals(BatterySipper.DrainType.WIFI.ordinal(), - StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__WIFI); + FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__WIFI); } private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah, diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 816bb8789667..692af584cd61 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -306,6 +306,7 @@ applications that come with the platform <permission name="android.permission.LOCAL_MAC_ADDRESS"/> <permission name="android.permission.MANAGE_ACCESSIBILITY"/> <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> + <permission name="android.permission.MANAGE_ROLLBACKS"/> <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> @@ -371,6 +372,7 @@ applications that come with the platform <permission name="android.permission.CONTROL_DEVICE_LIGHTS" /> <!-- Permission required for ShortcutManagerUsageTest CTS test. --> <permission name="android.permission.ACCESS_SHORTCUTS"/> + <permission name="android.permission.REBOOT"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 13dcb4cb6ed3..9da185b95279 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1183,12 +1183,6 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "292555239": { - "message": "ScreenRotation sill animating: mDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" - }, "292904800": { "message": "Deferring rotation, animation in progress.", "level": "VERBOSE", @@ -1693,6 +1687,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1346895820": { + "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, "1358462645": { "message": "Looking for focus: %s, flags=%d, canReceive=%b", "level": "VERBOSE", diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index 91a60c327bf0..c12159cfd7a4 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -43,7 +43,7 @@ public final class Outline { /** @hide */ public static final int MODE_ROUND_RECT = 1; /** @hide */ - public static final int MODE_CONVEX_PATH = 2; + public static final int MODE_PATH = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -51,7 +51,7 @@ public final class Outline { value = { MODE_EMPTY, MODE_ROUND_RECT, - MODE_CONVEX_PATH, + MODE_PATH, }) public @interface Mode {} @@ -60,7 +60,7 @@ public final class Outline { public int mMode = MODE_EMPTY; /** - * Only guaranteed to be non-null when mode == MODE_CONVEX_PATH + * Only guaranteed to be non-null when mode == MODE_PATH * * @hide */ @@ -124,7 +124,7 @@ public final class Outline { * @see android.view.View#setClipToOutline(boolean) */ public boolean canClip() { - return mMode != MODE_CONVEX_PATH; + return mMode != MODE_PATH; } /** @@ -157,7 +157,7 @@ public final class Outline { */ public void set(@NonNull Outline src) { mMode = src.mMode; - if (src.mMode == MODE_CONVEX_PATH) { + if (src.mMode == MODE_PATH) { if (mPath == null) { mPath = new Path(); } @@ -194,7 +194,7 @@ public final class Outline { return; } - if (mMode == MODE_CONVEX_PATH) { + if (mMode == MODE_PATH) { // rewind here to avoid thrashing the allocations, but could alternately clear ref mPath.rewind(); } @@ -213,7 +213,7 @@ public final class Outline { /** * Populates {@code outBounds} with the outline bounds, if set, and returns * {@code true}. If no outline bounds are set, or if a path has been set - * via {@link #setConvexPath(Path)}, returns {@code false}. + * via {@link #setPath(Path)}, returns {@code false}. * * @param outRect the rect to populate with the outline bounds, if set * @return {@code true} if {@code outBounds} was populated with outline @@ -229,7 +229,7 @@ public final class Outline { /** * Returns the rounded rect radius, if set, or a value less than 0 if a path has - * been set via {@link #setConvexPath(Path)}. A return value of {@code 0} + * been set via {@link #setPath(Path)}. A return value of {@code 0} * indicates a non-rounded rect. * * @return the rounded rect radius, or value < 0 @@ -259,7 +259,7 @@ public final class Outline { mPath.rewind(); } - mMode = MODE_CONVEX_PATH; + mMode = MODE_PATH; mPath.addOval(left, top, right, bottom, Path.Direction.CW); mRect.setEmpty(); mRadius = RADIUS_UNDEFINED; @@ -279,9 +279,21 @@ public final class Outline { * @param convexPath used to construct the Outline. As of * {@link android.os.Build.VERSION_CODES#Q}, it is no longer required to be * convex. + * + * @deprecated The path is no longer required to be convex. Use {@link #setPath} instead. */ + @Deprecated public void setConvexPath(@NonNull Path convexPath) { - if (convexPath.isEmpty()) { + setPath(convexPath); + } + + /** + * Sets the Outline to a {@link android.graphics.Path path}. + * + * @param path used to construct the Outline. + */ + public void setPath(@NonNull Path path) { + if (path.isEmpty()) { setEmpty(); return; } @@ -290,8 +302,8 @@ public final class Outline { mPath = new Path(); } - mMode = MODE_CONVEX_PATH; - mPath.set(convexPath); + mMode = MODE_PATH; + mPath.set(path); mRect.setEmpty(); mRadius = RADIUS_UNDEFINED; } @@ -302,7 +314,7 @@ public final class Outline { public void offset(int dx, int dy) { if (mMode == MODE_ROUND_RECT) { mRect.offset(dx, dy); - } else if (mMode == MODE_CONVEX_PATH) { + } else if (mMode == MODE_PATH) { mPath.offset(dx, dy); } } diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 17e3b4465130..3835b2d493c5 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -687,8 +687,8 @@ public final class RenderNode { outline.mRect.left, outline.mRect.top, outline.mRect.right, outline.mRect.bottom, outline.mRadius, outline.mAlpha); - case Outline.MODE_CONVEX_PATH: - return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath, + case Outline.MODE_PATH: + return nSetOutlinePath(mNativeRenderNode, outline.mPath.mNativePath, outline.mAlpha); } @@ -1620,7 +1620,7 @@ public final class RenderNode { int right, int bottom, float radius, float alpha); @CriticalNative - private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath, + private static native boolean nSetOutlinePath(long renderNode, long nativePath, float alpha); @CriticalNative diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 928e607abbbe..746378e10bc7 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -387,7 +387,7 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback @Override public void getOutline(@NonNull Outline outline) { - outline.setConvexPath(mMask); + outline.setPath(mMask); } /** @hide */ diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 3881955d2632..f053f392b97e 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -1915,7 +1915,7 @@ public class GradientDrawable extends Drawable { case RECTANGLE: if (st.mRadiusArray != null) { buildPathIfDirty(); - outline.setConvexPath(mPath); + outline.setPath(mPath); return; } diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java index 475e0bb70f2b..28ba60577fb1 100644 --- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java +++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java @@ -94,7 +94,7 @@ public class RoundRectShape extends RectShape { for (int i = 1; i < 8; i++) { if (mOuterRadii[i] != radius) { // can't call simple constructors, use path - outline.setConvexPath(mPath); + outline.setPath(mPath); return; } } diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h index f1c38031980e..2eb2c7c7e299 100644 --- a/libs/hwui/Outline.h +++ b/libs/hwui/Outline.h @@ -26,7 +26,7 @@ namespace uirenderer { class Outline { public: - enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 }; + enum class Type { None = 0, Empty = 1, Path = 2, RoundRect = 3 }; Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {} @@ -57,12 +57,12 @@ public: } } - void setConvexPath(const SkPath* outline, float alpha) { + void setPath(const SkPath* outline, float alpha) { if (!outline) { setEmpty(); return; } - mType = Type::ConvexPath; + mType = Type::Path; mPath = *outline; mBounds.set(outline->getBounds()); mAlpha = alpha; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 699b96a685c9..c1435d1ea2d5 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -700,7 +700,7 @@ void CanvasContext::enqueueFrameWork(std::function<void()>&& func) { int64_t CanvasContext::getFrameNumber() { // mFrameNumber is reset to -1 when the surface changes or we swap buffers if (mFrameNumber == -1 && mNativeSurface.get()) { - mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber()); + mFrameNumber = ANativeWindow_getNextFrameId(mNativeSurface->getNativeWindow()); } return mFrameNumber; } diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h index 32472539f616..da5097ce33f0 100644 --- a/libs/hwui/renderthread/ReliableSurface.h +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -43,8 +43,6 @@ public: int query(int what, int* value) const { return mSurface->query(what, value); } - uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); } - int getAndClearError() { int ret = mBufferQueueState; mBufferQueueState = OK; diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp index e075d806126b..06f158f25fc5 100644 --- a/libs/hwui/tests/common/TestContext.cpp +++ b/libs/hwui/tests/common/TestContext.cpp @@ -22,43 +22,50 @@ namespace android { namespace uirenderer { namespace test { -static const int IDENT_DISPLAYEVENT = 1; - -static android::DisplayInfo DUMMY_DISPLAY{ - 1080, // w - 1920, // h - 320.0, // xdpi - 320.0, // ydpi - 60.0, // fps - 2.0, // density - ui::ROTATION_0, // orientation - false, // secure? - 0, // appVsyncOffset - 0, // presentationDeadline -}; - -DisplayInfo getInternalDisplay() { -#if !HWUI_NULL_GPU - DisplayInfo display; - const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken(); - LOG_ALWAYS_FATAL_IF(token == nullptr, - "Failed to get display info because internal display is disconnected\n"); - status_t status = SurfaceComposerClient::getDisplayInfo(token, &display); - LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); - return display; +const DisplayInfo& getDisplayInfo() { + static DisplayInfo info = [] { + DisplayInfo info; +#if HWUI_NULL_GPU + info.density = 2.f; #else - return DUMMY_DISPLAY; + const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken(); + LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__); + + const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info); + LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get display info", __FUNCTION__); #endif + return info; + }(); + + return info; } -// Initialize to a dummy default -android::DisplayInfo gDisplay = DUMMY_DISPLAY; +const DisplayConfig& getActiveDisplayConfig() { + static DisplayConfig config = [] { + DisplayConfig config; +#if HWUI_NULL_GPU + config.resolution = ui::Size(1080, 1920); + config.xDpi = config.yDpi = 320.f; + config.refreshRate = 60.f; +#else + const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken(); + LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__); + + const status_t status = SurfaceComposerClient::getActiveDisplayConfig(token, &config); + LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get active display config", __FUNCTION__); +#endif + return config; + }(); + + return config; +} TestContext::TestContext() { mLooper = new Looper(true); mSurfaceComposerClient = new SurfaceComposerClient(); - mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT, Looper::EVENT_INPUT, nullptr, - nullptr); + + constexpr int EVENT_ID = 1; + mLooper->addFd(mDisplayEventReceiver.getFd(), EVENT_ID, Looper::EVENT_INPUT, nullptr, nullptr); } TestContext::~TestContext() {} @@ -79,8 +86,10 @@ void TestContext::createSurface() { } void TestContext::createWindowSurface() { - mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), gDisplay.w, - gDisplay.h, PIXEL_FORMAT_RGBX_8888); + const ui::Size& resolution = getActiveDisplayResolution(); + mSurfaceControl = + mSurfaceComposerClient->createSurface(String8("HwuiTest"), resolution.getWidth(), + resolution.getHeight(), PIXEL_FORMAT_RGBX_8888); SurfaceComposerClient::Transaction t; t.setLayer(mSurfaceControl, 0x7FFFFFF).show(mSurfaceControl).apply(); @@ -94,7 +103,8 @@ void TestContext::createOffscreenSurface() { producer->setMaxDequeuedBufferCount(3); producer->setAsyncMode(true); mConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_COMPOSER, 4); - mConsumer->setDefaultBufferSize(gDisplay.w, gDisplay.h); + const ui::Size& resolution = getActiveDisplayResolution(); + mConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); mSurface = new Surface(producer); } diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h index 116d4de8090a..a012ecb1a1d3 100644 --- a/libs/hwui/tests/common/TestContext.h +++ b/libs/hwui/tests/common/TestContext.h @@ -23,20 +23,25 @@ #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceControl.h> +#include <ui/DisplayConfig.h> #include <ui/DisplayInfo.h> #include <utils/Looper.h> #include <atomic> #include <thread> +#define dp(x) ((x) * android::uirenderer::test::getDisplayInfo().density) + namespace android { namespace uirenderer { namespace test { -extern DisplayInfo gDisplay; -#define dp(x) ((x)*android::uirenderer::test::gDisplay.density) +const DisplayInfo& getDisplayInfo(); +const DisplayConfig& getActiveDisplayConfig(); -DisplayInfo getInternalDisplay(); +inline const ui::Size& getActiveDisplayResolution() { + return getActiveDisplayConfig().resolution; +} class TestContext { public: diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index 22d5abbd3dbc..3b6baa70db9a 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -109,16 +109,14 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options void run(const TestScene::Info& info, const TestScene::Options& opts, benchmark::BenchmarkReporter* reporter) { - // Switch to the real display - gDisplay = getInternalDisplay(); - Properties::forceDrawFrame = true; TestContext testContext; testContext.setRenderOffscreen(opts.renderOffscreen); // create the native surface - const int width = gDisplay.w; - const int height = gDisplay.h; + const ui::Size& resolution = getActiveDisplayResolution(); + const int width = resolution.getWidth(); + const int height = resolution.getHeight(); sp<Surface> surface = testContext.surface(); std::unique_ptr<TestScene> scene(info.createScene(opts)); diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java index 127d00c0afe2..d57148092754 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java @@ -24,12 +24,12 @@ import android.server.location.ServerLocationProtoEnums; import android.text.format.DateUtils; import android.util.Base64; import android.util.Log; -import android.util.StatsLog; import android.util.TimeUtils; import com.android.internal.app.IBatteryStats; import com.android.internal.location.nano.GnssLogsProto.GnssLog; import com.android.internal.location.nano.GnssLogsProto.PowerMetrics; +import com.android.internal.util.FrameworkStatsLog; import java.util.ArrayList; import java.util.Arrays; @@ -540,7 +540,7 @@ public class GnssMetrics { } int signalLevel = getSignalLevel(avgCn0); if (signalLevel != mLastSignalLevel) { - StatsLog.write(StatsLog.GPS_SIGNAL_QUALITY_CHANGED, signalLevel); + FrameworkStatsLog.write(FrameworkStatsLog.GPS_SIGNAL_QUALITY_CHANGED, signalLevel); mLastSignalLevel = signalLevel; } try { diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 114c0f1f6bf3..fe0c2d21d442 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -1427,7 +1427,10 @@ public final class AudioAttributes implements Parcelable { } } - static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) { + /** + * @hide + */ + public static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) { switch (capturePolicy) { case ALLOW_CAPTURE_BY_NONE: flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 861b76d2b153..7b17f9f764fb 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1547,23 +1547,22 @@ public class AudioManager { * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. - * @throws IllegalArgumentException if the argument is not a valid value. + * @throws RuntimeException if the argument is not a valid value. */ public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) { - int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0); - // TODO: got trough AudioService and save a cache to restore in case of AP crash // TODO: also pass the package in case multiple packages have the same UID - int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); - if (result != AudioSystem.AUDIO_STATUS_OK) { - Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); - return; + final IAudioService service = getService(); + try { + int result = service.setAllowedCapturePolicy(capturePolicy); + if (result != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); + return; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - mCapturePolicy = capturePolicy; } - @AudioAttributes.CapturePolicy - private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; - /** * Return the capture policy. * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or @@ -1571,7 +1570,13 @@ public class AudioManager { */ @AudioAttributes.CapturePolicy public int getAllowedCapturePolicy() { - return mCapturePolicy; + int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL; + try { + result = getService().getAllowedCapturePolicy(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to query allowed capture policy: " + e); + } + return result; } //==================================================================== diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 1f97be5c3f4d..64c5c05b5621 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -282,6 +282,10 @@ interface IAudioService { List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes); + int setAllowedCapturePolicy(in int capturePolicy); + + int getAllowedCapturePolicy(); + // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. } diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java index 85f3f72020d0..b40ab00afb30 100644 --- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java +++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java @@ -327,7 +327,7 @@ public class Atsc3FrontendSettings extends FrontendSettings { */ public static class Builder extends FrontendSettings.Builder<Builder> { private int mBandwidth; - private byte mDemodOutputFormat; + private int mDemodOutputFormat; private Atsc3PlpSettings[] mPlpSettings; private Builder() { @@ -345,7 +345,7 @@ public class Atsc3FrontendSettings extends FrontendSettings { * Sets Demod Output Format. */ @NonNull - public Builder setDemodOutputFormat(byte demodOutputFormat) { + public Builder setDemodOutputFormat(@DemodOutputFormat int demodOutputFormat) { mDemodOutputFormat = demodOutputFormat; return this; } diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java index bfa4f3f027a4..705d5207cc5f 100644 --- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java +++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java @@ -147,11 +147,11 @@ public class DvbcFrontendSettings extends FrontendSettings { private final long mFec; private final int mSymbolRate; private final int mOuterFec; - private final byte mAnnex; + private final int mAnnex; private final int mSpectralInversion; private DvbcFrontendSettings(int frequency, int modulation, long fec, int symbolRate, - int outerFec, byte annex, int spectralInversion) { + int outerFec, int annex, int spectralInversion) { super(frequency); mModulation = modulation; mFec = fec; @@ -192,7 +192,7 @@ public class DvbcFrontendSettings extends FrontendSettings { * Gets Annex. */ @Annex - public byte getAnnex() { + public int getAnnex() { return mAnnex; } /** @@ -223,7 +223,7 @@ public class DvbcFrontendSettings extends FrontendSettings { private long mFec; private int mSymbolRate; private int mOuterFec; - private byte mAnnex; + private int mAnnex; private int mSpectralInversion; private Builder() { @@ -265,7 +265,7 @@ public class DvbcFrontendSettings extends FrontendSettings { * Sets Annex. */ @NonNull - public Builder setAnnex(@Annex byte annex) { + public Builder setAnnex(@Annex int annex) { mAnnex = annex; return this; } diff --git a/native/android/Android.bp b/native/android/Android.bp index 34ab7a0a0770..0c6f507787d9 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -64,7 +64,6 @@ cc_library_shared { "libgui", "libharfbuzz_ng", // Only for including hb.h via minikin "libsensor", - "libstats_jni", "libandroid_runtime", "libminikin", "libnetd_client", diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index e2297e44fdfe..d2f514c6c0ca 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -29,6 +29,9 @@ <bool name="config_enableRightNavigationBar">false</bool> <bool name="config_enableBottomNavigationBar">true</bool> + <!-- Disable normal notification rendering; we handle that ourselves --> + <bool name="config_renderNotifications">false</bool> + <!-- Whether heads-up notifications should be shown when shade is open. --> <bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool> diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index cf4ee7d97409..585acfec410a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -22,7 +22,6 @@ import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; import android.content.Context; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; -import com.android.systemui.car.CarNotificationEntryManager; import com.android.systemui.car.CarNotificationInterruptionStateProvider; import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dock.DockManager; @@ -73,13 +72,6 @@ abstract class CarSystemUIModule { return false; } - /** - * Use {@link CarNotificationEntryManager}, which does nothing when adding a notification. - */ - @Binds - abstract NotificationEntryManager bindNotificationEntryManager( - CarNotificationEntryManager notificationEntryManager); - @Singleton @Provides static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context, diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java deleted file mode 100644 index cfe1c702663e..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.car; - -import android.service.notification.NotificationListenerService; -import android.service.notification.StatusBarNotification; - -import com.android.systemui.statusbar.FeatureFlags; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; -import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.util.leak.LeakDetector; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.Lazy; - -/** - * Car specific notification entry manager that does nothing when adding a notification. - * - * <p> This is because system UI notifications are disabled and we have a different implementation. - * Please see {@link com.android.car.notification}. - */ -@Singleton -public class CarNotificationEntryManager extends NotificationEntryManager { - - @Inject - public CarNotificationEntryManager( - NotifLog notifLog, - NotificationGroupManager groupManager, - NotificationRankingManager rankingManager, - KeyguardEnvironment keyguardEnvironment, - FeatureFlags featureFlags, - Lazy<NotificationRowBinder> notificationRowBinderLazy, - Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy, - LeakDetector leakDetector) { - super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags, - notificationRowBinderLazy, notificationRemoteInputManagerLazy, leakDetector); - } - - @Override - public void addNotification( - StatusBarNotification notification, NotificationListenerService.RankingMap ranking) { - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 76e9ec64e2f2..210dd321933a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -87,10 +87,8 @@ import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -103,12 +101,10 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -124,7 +120,6 @@ import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ScrimController; @@ -141,7 +136,6 @@ import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.volume.VolumeComponent; @@ -257,7 +251,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt public CarStatusBar( Context context, - FeatureFlags featureFlags, + NotificationsController notificationsController, LightBarController lightBarController, AutoHideController autoHideController, KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -269,13 +263,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NotifPipelineInitializer> notifPipelineInitializer, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, NotificationInterruptionStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, @@ -296,12 +288,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt VibratorHelper vibratorHelper, BubbleController bubbleController, NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, Lazy<AssistManager> assistManagerLazy, - NotificationListener notificationListener, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, LockscreenLockIconController lockscreenLockIconController, @@ -318,7 +308,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt Optional<Recents> recents, Provider<StatusBarComponent.Builder> statusBarComponentBuilder, PluginManager pluginManager, - RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, SuperStatusBarViewFactory superStatusBarViewFactory, LightsOutNotifController lightsOutNotifController, @@ -334,7 +323,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, - NotificationRowBinderImpl notificationRowBinder, DismissCallbackRegistry dismissCallbackRegistry, /* Car Settings injected components. */ CarServiceProvider carServiceProvider, @@ -345,7 +333,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt FlingAnimationUtils.Builder flingAnimationUtilsBuilder) { super( context, - featureFlags, + notificationsController, lightBarController, autoHideController, keyguardUpdateMonitor, @@ -357,13 +345,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, - notifPipelineInitializer, falsingManager, broadcastDispatcher, remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationEntryManager, notificationInterruptionStateProvider, notificationViewHierarchyManager, keyguardViewMediator, @@ -384,12 +370,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt vibratorHelper, bubbleController, groupManager, - groupAlertTransferHelper, visualStabilityManager, deviceProvisionedController, navigationBarController, assistManagerLazy, - notificationListener, configurationController, notificationShadeWindowController, lockscreenLockIconController, @@ -407,7 +391,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt recents, statusBarComponentBuilder, pluginManager, - remoteInputUriController, dividerOptional, lightsOutNotifController, statusBarNotificationActivityStarterBuilder, @@ -422,7 +405,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt keyguardDismissUtil, extensionController, userInfoControllerImpl, - notificationRowBinder, dismissCallbackRegistry); mUserSwitcherController = userSwitcherController; mScrimController = scrimController; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index 45da8223943b..498bd8780f29 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -47,10 +47,8 @@ import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -63,12 +61,10 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -83,7 +79,6 @@ import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ScrimController; @@ -99,7 +94,6 @@ import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.volume.VolumeComponent; @@ -127,7 +121,7 @@ public class CarStatusBarModule { @Singleton static CarStatusBar provideStatusBar( Context context, - FeatureFlags featureFlags, + NotificationsController notificationsController, LightBarController lightBarController, AutoHideController autoHideController, KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -139,13 +133,11 @@ public class CarStatusBarModule { HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NotifPipelineInitializer> notifPipelineInitializer, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, NotificationInterruptionStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, @@ -166,12 +158,10 @@ public class CarStatusBarModule { VibratorHelper vibratorHelper, BubbleController bubbleController, NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, Lazy<AssistManager> assistManagerLazy, - NotificationListener notificationListener, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, LockscreenLockIconController lockscreenLockIconController, @@ -188,7 +178,6 @@ public class CarStatusBarModule { Optional<Recents> recentsOptional, Provider<StatusBarComponent.Builder> statusBarComponentBuilder, PluginManager pluginManager, - RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, SuperStatusBarViewFactory superStatusBarViewFactory, LightsOutNotifController lightsOutNotifController, @@ -204,7 +193,6 @@ public class CarStatusBarModule { KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, - NotificationRowBinderImpl notificationRowBinder, DismissCallbackRegistry dismissCallbackRegistry, CarServiceProvider carServiceProvider, Lazy<PowerManagerHelper> powerManagerHelperLazy, @@ -214,7 +202,7 @@ public class CarStatusBarModule { FlingAnimationUtils.Builder flingAnimationUtilsBuilder) { return new CarStatusBar( context, - featureFlags, + notificationsController, lightBarController, autoHideController, keyguardUpdateMonitor, @@ -226,13 +214,11 @@ public class CarStatusBarModule { headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, - notifPipelineInitializer, falsingManager, broadcastDispatcher, remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationEntryManager, notificationInterruptionStateProvider, notificationViewHierarchyManager, keyguardViewMediator, @@ -253,12 +239,10 @@ public class CarStatusBarModule { vibratorHelper, bubbleController, groupManager, - groupAlertTransferHelper, visualStabilityManager, deviceProvisionedController, navigationBarController, assistManagerLazy, - notificationListener, configurationController, notificationShadeWindowController, lockscreenLockIconController, @@ -275,7 +259,6 @@ public class CarStatusBarModule { recentsOptional, statusBarComponentBuilder, pluginManager, - remoteInputUriController, dividerOptional, superStatusBarViewFactory, lightsOutNotifController, @@ -290,7 +273,6 @@ public class CarStatusBarModule { keyguardDismissUtil, extensionController, userInfoControllerImpl, - notificationRowBinder, dismissCallbackRegistry, carServiceProvider, powerManagerHelperLazy, diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml index 066e8f6bcbaf..199476f47be0 100644 --- a/packages/CarrierDefaultApp/res/values-ky/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml @@ -12,6 +12,6 @@ <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Мобилдик Интернеттин абалы"</string> <string name="action_bar_label" msgid="4290345990334377177">"Мобилдик тармакка кирүү"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string> - <string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, каттоо эсебине кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string> + <string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string> <string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index 99c7dcf52818..d287f95e504a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -74,6 +74,21 @@ public class InfoMediaDevice extends MediaDevice { } @Override + public void requestSetVolume(int volume) { + mRouterManager.requestSetVolume(mRouteInfo, volume); + } + + @Override + public int getMaxVolume() { + return mRouteInfo.getVolumeMax(); + } + + @Override + public int getCurrentVolume() { + return mRouteInfo.getVolume(); + } + + @Override public void disconnect() { //TODO(b/144535188): disconnected last select device } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 53a852069478..839d528406cd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -109,6 +109,59 @@ public abstract class MediaDevice implements Comparable<MediaDevice> { public abstract boolean isConnected(); /** + * Request to set volume. + * + * @param volume is the new value. + */ + public void requestSetVolume(int volume) { + } + + /** + * Get max volume from MediaDevice. + * + * @return max volume. + */ + public int getMaxVolume() { + return 100; + } + + /** + * Get current volume from MediaDevice. + * + * @return current volume. + */ + public int getCurrentVolume() { + return 0; + } + + /** + * Get application package name. + * + * @return package name. + */ + public String getClientPackageName() { + return null; + } + + /** + * Get application label from MediaDevice. + * + * @return application label. + */ + public String getClientAppLabel() { + return null; + } + + /** + * Get application label from MediaDevice. + * + * @return application label. + */ + public int getDeviceType() { + return mType; + } + + /** * Rules: * 1. If there is one of the connected devices identified as a carkit, this carkit will * be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule. diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index 78ccba02fb04..d4e0510e15a7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -60,7 +60,7 @@ public class WifiUtils { if (config != null) { WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); - for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE; + for (int index = WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE; index < WifiConfiguration.NetworkSelectionStatus .NETWORK_SELECTION_DISABLED_MAX; index++) { if (networkStatus.getDisableReasonCounter(index) != 0) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 3c52f543c81b..44864a61ade6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -626,7 +626,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { * Get names of the settings for which the current value should be preserved during restore. */ private Set<String> getSettingsToPreserveInRestore(Uri settingsUri) { - if (!FeatureFlagUtils.isEnabled(getApplicationContext(), + if (!FeatureFlagUtils.isEnabled(getBaseContext(), FeatureFlagUtils.SETTINGS_DO_NOT_RESTORE_PRESERVED)) { return Collections.emptySet(); } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 84d9bb673d1f..6a89b71be897 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -91,6 +91,7 @@ <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" /> <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> + <uses-permission android:name="android.permission.REBOOT" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> <uses-permission android:name="android.permission.POWER_SAVER" /> <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" /> @@ -253,6 +254,9 @@ <!-- Permission required for CTS test - CtsLightsManagerTest --> <uses-permission android:name="android.permission.CONTROL_DEVICE_LIGHTS" /> + <!-- Permission needed to test mainline permission module rollback --> + <uses-permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 26fa1cf46974..149eaf47b97d 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -646,6 +646,7 @@ android:label="Controls Providers" android:theme="@style/Theme.SystemUI" android:exported="true" + android:showForAllUsers="true" android:excludeFromRecents="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" android:visibleToInstantApps="true"> @@ -655,6 +656,7 @@ android:parentActivityName=".controls.management.ControlsProviderSelectorActivity" android:theme="@style/Theme.SystemUI" android:excludeFromRecents="true" + android:showForAllUsers="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" android:visibleToInstantApps="true"> </activity> diff --git a/packages/SystemUI/res/color/lock_background.xml b/packages/SystemUI/res/color/control_background.xml index 646fe5dfe712..646fe5dfe712 100644 --- a/packages/SystemUI/res/color/lock_background.xml +++ b/packages/SystemUI/res/color/control_background.xml diff --git a/packages/SystemUI/res/color/unknown_foreground.xml b/packages/SystemUI/res/color/control_foreground.xml index bf028f18a7de..bf028f18a7de 100644 --- a/packages/SystemUI/res/color/unknown_foreground.xml +++ b/packages/SystemUI/res/color/control_foreground.xml diff --git a/packages/SystemUI/res/color/thermo_cool_background.xml b/packages/SystemUI/res/color/thermo_cool_background.xml new file mode 100644 index 000000000000..646fe5dfe712 --- /dev/null +++ b/packages/SystemUI/res/color/thermo_cool_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_blue_50" /> +</selector> diff --git a/packages/SystemUI/res/color/thermo_cool_foreground.xml b/packages/SystemUI/res/color/thermo_cool_foreground.xml new file mode 100644 index 000000000000..bf028f18a7de --- /dev/null +++ b/packages/SystemUI/res/color/thermo_cool_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_blue_700" /> + </selector> diff --git a/packages/SystemUI/res/color/thermo_heat_background.xml b/packages/SystemUI/res/color/thermo_heat_background.xml new file mode 100644 index 000000000000..6f29ed5f60ac --- /dev/null +++ b/packages/SystemUI/res/color/thermo_heat_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_red_50" /> +</selector> diff --git a/packages/SystemUI/res/color/lock_foreground.xml b/packages/SystemUI/res/color/thermo_heat_foreground.xml index 3e05653bce92..72f4b8d13458 100644 --- a/packages/SystemUI/res/color/lock_foreground.xml +++ b/packages/SystemUI/res/color/thermo_heat_foreground.xml @@ -2,5 +2,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:color="@color/control_default_foreground" /> - <item android:color="@color/GM2_blue_700" /> + <item android:color="@color/GM2_red_700" /> </selector> diff --git a/packages/SystemUI/res/drawable/qs_media_background.xml b/packages/SystemUI/res/drawable/qs_media_background.xml new file mode 100644 index 000000000000..2821e4c28bab --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_media_background.xml @@ -0,0 +1,26 @@ +<?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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorBackgroundFloating" /> + <corners + android:bottomLeftRadius="@dimen/qs_media_corner_radius" + android:topLeftRadius="@dimen/qs_media_corner_radius" + android:bottomRightRadius="@dimen/qs_media_corner_radius" + android:topRightRadius="@dimen/qs_media_corner_radius" + /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml index e91f840fe238..149446c55fc5 100644 --- a/packages/SystemUI/res/layout/media_carousel.xml +++ b/packages/SystemUI/res/layout/media_carousel.xml @@ -19,7 +19,7 @@ <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="@dimen/qs_media_height" + android:layout_height="wrap_content" android:padding="@dimen/qs_media_padding" android:scrollbars="none" android:visibility="gone" diff --git a/packages/SystemUI/res/layout/qqs_media_panel.xml b/packages/SystemUI/res/layout/qqs_media_panel.xml index 1189371fc7f1..403b5dc3a427 100644 --- a/packages/SystemUI/res/layout/qqs_media_panel.xml +++ b/packages/SystemUI/res/layout/qqs_media_panel.xml @@ -23,20 +23,25 @@ android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" - android:padding="10dp" + android:paddingTop="16dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingBottom="12dp" + android:background="@drawable/qs_media_background" > - <!-- Top line: icon + artist name --> + <!-- Top line: icon + song name --> <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clipChildren="false" android:gravity="center" + android:layout_marginBottom="12dp" > <com.android.internal.widget.CachingIconView android:id="@+id/icon" - android:layout_width="15dp" - android:layout_height="15dp" + android:layout_width="14dp" + android:layout_height="14dp" android:layout_marginEnd="5dp" /> <TextView @@ -48,15 +53,6 @@ /> </LinearLayout> - <!-- Second line: song name --> - <TextView - android:id="@+id/header_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:fontFamily="@*android:string/config_bodyFontFamily" - android:gravity="center"/> - <!-- Bottom section: controls --> <LinearLayout android:id="@+id/media_actions" @@ -70,8 +66,6 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" android:gravity="center" android:visibility="gone" android:id="@+id/action0" @@ -80,8 +74,6 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" android:gravity="center" android:visibility="gone" android:id="@+id/action1" @@ -90,8 +82,6 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" android:gravity="center" android:visibility="gone" android:id="@+id/action2" diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index a02962e5e1e6..0c9ce3938420 100644 --- a/packages/SystemUI/res/layout/qs_footer_impl.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -130,9 +130,10 @@ </LinearLayout> <View android:id="@+id/qs_drag_handle_view" - android:layout_width="24dp" + android:layout_width="48dp" android:layout_height="4dp" - android:layout_marginBottom="16dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" android:layout_gravity="center_horizontal|bottom" android:background="@drawable/qs_footer_drag_handle" /> diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml index dd422766c153..22303dc1d8d2 100644 --- a/packages/SystemUI/res/layout/qs_media_panel.xml +++ b/packages/SystemUI/res/layout/qs_media_panel.xml @@ -23,50 +23,116 @@ android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal|fill_vertical" - android:padding="10dp" + android:padding="16dp" + android:background="@drawable/qs_media_background" > - <!-- placeholder for notification header --> + <!-- Header section --> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/header" - android:padding="3dp" - android:layout_marginEnd="-12dp" + android:layout_marginBottom="16dp" + > + + <ImageView + android:id="@+id/album_art" + android:layout_width="@dimen/qs_media_album_size" + android:layout_height="@dimen/qs_media_album_size" + android:layout_marginRight="16dp" + android:layout_weight="0" /> - <!-- Top line: artist name --> - <LinearLayout - android:orientation="horizontal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="@dimen/qs_media_album_size" + android:layout_weight="1" > - <TextView - android:id="@+id/header_title" - android:layout_width="wrap_content" + <LinearLayout + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + > + <com.android.internal.widget.CachingIconView + android:id="@+id/icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_marginEnd="5dp" + /> + <TextView + android:id="@+id/app_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + android:singleLine="true" + /> + </LinearLayout> + + <!-- Song name --> + <TextView + android:id="@+id/header_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" + android:textSize="18sp" + android:paddingBottom="6dp" + android:gravity="center"/> + + <!-- Artist name --> + <TextView + android:id="@+id/header_artist" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:textSize="14sp" + android:singleLine="true" + /> + </LinearLayout> + + <!-- Output chip --> + <LinearLayout + android:layout_width="0dp" android:layout_height="wrap_content" - android:fontFamily="@*android:string/config_headlineFontFamilyMedium" - android:singleLine="true" - /> + android:orientation="horizontal" + android:visibility="gone" + android:paddingTop="6dp" + android:paddingBottom="6dp" + android:paddingLeft="12dp" + android:paddingRight="12dp" + android:gravity="center" + android:id="@+id/media_seamless" + android:background="@*android:drawable/media_seamless_background" + android:layout_weight="1" + > + <ImageView + android:layout_width="@dimen/qs_seamless_icon_size" + android:layout_height="@dimen/qs_seamless_icon_size" + android:src="@*android:drawable/ic_media_seamless" + android:layout_marginRight="8dp" + android:id="@+id/media_seamless_image" + /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:text="@*android:string/ext_media_seamless_action" + android:textSize="14sp" + android:id="@+id/media_seamless_text" + android:singleLine="true" + /> + </LinearLayout> </LinearLayout> - <!-- Second line: song name --> - <TextView - android:id="@+id/header_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:fontFamily="@*android:string/config_bodyFontFamily" - android:gravity="center"/> - - <!-- Bottom section: controls --> + <!-- Controls --> <LinearLayout android:id="@+id/media_actions" android:orientation="horizontal" android:layoutDirection="ltr" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" > @@ -74,8 +140,8 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:gravity="center" android:visibility="gone" android:id="@+id/action0" @@ -84,18 +150,18 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:gravity="center" android:visibility="gone" android:id="@+id/action1" /> <ImageButton style="@android:style/Widget.Material.Button.Borderless.Small" - android:layout_width="48dp" - android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" + android:layout_width="52dp" + android:layout_height="52dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:gravity="center" android:visibility="gone" android:id="@+id/action2" @@ -104,8 +170,8 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:gravity="center" android:visibility="gone" android:id="@+id/action3" @@ -114,8 +180,8 @@ style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="48dp" android:layout_height="48dp" - android:padding="8dp" - android:layout_marginEnd="2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" android:gravity="center" android:visibility="gone" android:id="@+id/action4" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 2aa6d9512898..d72ce5eea78d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -328,6 +328,10 @@ <item type="id" name="action_toggle_overview"/> + <!-- Whether or not to show notifications to the user. If disabled, SystemUI will still be + registered as a notification listener, but will ignore all notification events. --> + <bool name="config_renderNotifications">true</bool> + <!-- Whether or not the gear icon on notifications should be shown. The gear is shown when the the notification is not swiped enough to dismiss it. --> <bool name="config_showNotificationGear">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1f9fb0511d26..33cabc1fea52 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1164,10 +1164,12 @@ <dimen name="new_qs_vertical_margin">8dp</dimen> <!-- Size of media cards in the QSPanel carousel --> - <dimen name="qs_media_height">150dp</dimen> <dimen name="qs_media_width">350dp</dimen> <dimen name="qs_media_padding">8dp</dimen> <dimen name="qs_media_corner_radius">10dp</dimen> + <dimen name="qs_media_album_size">72dp</dimen> + <dimen name="qs_seamless_icon_size">20dp</dimen> + <dimen name="qqs_media_spacing">8dp</dimen> <dimen name="magnification_border_size">5dp</dimen> <dimen name="magnification_frame_move_short">5dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 1f13f8dc02fe..fb8df5bfc7ce 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -196,7 +196,7 @@ <!-- text to show in place of RemoteInput images when they cannot be shown. [CHAR LIMIT=50] --> - <string name="remote_input_image_insertion_text">Image inserted</string> + <string name="remote_input_image_insertion_text">sent an image</string> <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] --> <string name="screenshot_saving_ticker">Saving screenshot\u2026</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java index 557845c34bf2..356e0ca7193c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java @@ -40,7 +40,7 @@ import java.util.function.Consumer; * @param <R> The proto class type of the entry root proto in the buffer */ public class FrameProtoTracer<P, S extends P, T extends P, R> - implements TraceBuffer.ProtoProvider<P, S, T>, Choreographer.FrameCallback { + implements Choreographer.FrameCallback { private static final String TAG = "FrameProtoTracer"; private static final int BUFFER_CAPACITY = 1024 * 1024; @@ -57,6 +57,25 @@ public class FrameProtoTracer<P, S extends P, T extends P, R> private volatile boolean mEnabled; private boolean mFrameScheduled; + private final TraceBuffer.ProtoProvider<P, S, T> mProvider = + new TraceBuffer.ProtoProvider<P, S, T>() { + @Override + public int getItemSize(P proto) { + return mParams.getProtoSize(proto); + } + + @Override + public byte[] getBytes(P proto) { + return mParams.getProtoBytes(proto); + } + + @Override + public void write(S encapsulatingProto, Queue<T> buffer, OutputStream os) + throws IOException { + os.write(mParams.serializeEncapsulatingProto(encapsulatingProto, buffer)); + } + }; + public interface ProtoTraceParams<P, S, T, R> { File getTraceFile(); S getEncapsulatingTraceProto(); @@ -68,7 +87,7 @@ public class FrameProtoTracer<P, S extends P, T extends P, R> public FrameProtoTracer(ProtoTraceParams<P, S, T, R> params) { mParams = params; - mBuffer = new TraceBuffer<>(BUFFER_CAPACITY, this, new Consumer<T>() { + mBuffer = new TraceBuffer<>(BUFFER_CAPACITY, mProvider, new Consumer<T>() { @Override public void accept(T t) { onProtoDequeued(t); @@ -78,21 +97,6 @@ public class FrameProtoTracer<P, S extends P, T extends P, R> mChoreographer = Choreographer.getMainThreadInstance(); } - @Override - public int getItemSize(P proto) { - return mParams.getProtoSize(proto); - } - - @Override - public byte[] getBytes(P proto) { - return mParams.getProtoBytes(proto); - } - - @Override - public void write(S encapsulatingProto, Queue<T> buffer, OutputStream os) throws IOException { - os.write(mParams.serializeEncapsulatingProto(encapsulatingProto, buffer)); - } - public void start() { synchronized (mLock) { if (mEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index eab970626bf1..924d16dd27d7 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -89,7 +89,7 @@ public class ForegroundServiceNotificationListener { } @Override - public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) { + public void onEntryRemoved(NotificationEntry entry, int reason) { removeNotification(entry.getSbn()); } }); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index fa1392644735..50a50633f43c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -448,12 +448,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList int bottomInset = getRootWindowInsets() != null ? getRootWindowInsets().getStableInsetBottom() : 0; - int mh = mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight + return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight - mPointerMargin - bottomInset; - Log.i(TAG, "max exp height: " + mh); -// return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight -// - mPointerMargin - bottomInset; - return mh; } /** diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java index 4194352f93bd..5b9ea7dd5e3a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java @@ -431,7 +431,7 @@ public class BubbleFlyoutView extends FrameLayout { final float interpolatedRadius = getInterpolatedRadius(); rectPath.addRoundRect(mBgRect, interpolatedRadius, interpolatedRadius, Path.Direction.CW); - outline.setConvexPath(rectPath); + outline.setPath(rectPath); // Get rid of the triangle path once it has disappeared behind the flyout. if (mPercentStillFlyout > 0.5f) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt index e6cdf50580d8..53841e2f144b 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt @@ -18,4 +18,8 @@ package com.android.systemui.controls import android.service.controls.Control -data class ControlStatus(val control: Control, val favorite: Boolean, val removed: Boolean = false)
\ No newline at end of file +data class ControlStatus( + val control: Control, + val favorite: Boolean, + val removed: Boolean = false +)
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt index 265ddd8043b6..588ef5c4e68f 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt @@ -22,7 +22,7 @@ import com.android.settingslib.applications.DefaultAppInfo class ControlsServiceInfo( context: Context, - serviceInfo: ServiceInfo + val serviceInfo: ServiceInfo ) : DefaultAppInfo( context, context.packageManager, diff --git a/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt new file mode 100644 index 000000000000..4f39f2255a75 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt @@ -0,0 +1,25 @@ +/* + * 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.controls + +import android.os.UserHandle + +interface UserAwareController { + + fun changeUser(newUser: UserHandle) {} + val currentUserId: Int +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt index 6b7fc4b7e827..12c3ce9c69ee 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt @@ -19,8 +19,9 @@ package com.android.systemui.controls.controller import android.content.ComponentName import android.service.controls.Control import android.service.controls.actions.ControlAction +import com.android.systemui.controls.UserAwareController -interface ControlsBindingController { +interface ControlsBindingController : UserAwareController { fun bindAndLoad(component: ComponentName, callback: (List<Control>) -> Unit) fun bindServices(components: List<ComponentName>) fun subscribe(controls: List<ControlInfo>) diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 2db2cf1af191..0a2a9255c3ea 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -19,6 +19,7 @@ package com.android.systemui.controls.controller import android.content.ComponentName import android.content.Context import android.os.IBinder +import android.os.UserHandle import android.service.controls.Control import android.service.controls.IControlsActionCallback import android.service.controls.IControlsLoadCallback @@ -50,12 +51,17 @@ open class ControlsBindingControllerImpl @Inject constructor( private val refreshing = AtomicBoolean(false) + private var currentUser = context.user + + override val currentUserId: Int + get() = currentUser.identifier + @GuardedBy("componentMap") private val tokenMap: MutableMap<IBinder, ControlsProviderLifecycleManager> = ArrayMap<IBinder, ControlsProviderLifecycleManager>() @GuardedBy("componentMap") - private val componentMap: MutableMap<ComponentName, ControlsProviderLifecycleManager> = - ArrayMap<ComponentName, ControlsProviderLifecycleManager>() + private val componentMap: MutableMap<Key, ControlsProviderLifecycleManager> = + ArrayMap<Key, ControlsProviderLifecycleManager>() private val loadCallbackService = object : IControlsLoadCallback.Stub() { override fun accept(token: IBinder, controls: MutableList<Control>) { @@ -103,6 +109,7 @@ open class ControlsBindingControllerImpl @Inject constructor( loadCallbackService, actionCallbackService, subscriberService, + currentUser, component ) } @@ -110,7 +117,7 @@ open class ControlsBindingControllerImpl @Inject constructor( private fun retrieveLifecycleManager(component: ComponentName): ControlsProviderLifecycleManager { synchronized(componentMap) { - val provider = componentMap.getOrPut(component) { + val provider = componentMap.getOrPut(Key(component, currentUser)) { createProviderManager(component) } tokenMap.putIfAbsent(provider.token, provider) @@ -137,7 +144,7 @@ open class ControlsBindingControllerImpl @Inject constructor( val providersWithFavorites = controlsByComponentName.keys synchronized(componentMap) { componentMap.forEach { - if (it.key !in providersWithFavorites) { + if (it.key.component !in providersWithFavorites) { backgroundExecutor.execute { it.value.unbindService() } } } @@ -163,8 +170,38 @@ open class ControlsBindingControllerImpl @Inject constructor( override fun bindServices(components: List<ComponentName>) { components.forEach { val provider = retrieveLifecycleManager(it) - backgroundExecutor.execute { provider.bindPermanently() } + backgroundExecutor.execute { provider.bindService() } + } + } + + override fun changeUser(newUser: UserHandle) { + if (newUser == currentUser) return + synchronized(componentMap) { + unbindAllProvidersLocked() // unbind all providers from the old user } + refreshing.set(false) + currentUser = newUser + } + + private fun unbindAllProvidersLocked() { + componentMap.values.forEach { + if (it.user == currentUser) { + it.unbindService() + } + } + } + + override fun toString(): String { + return StringBuilder(" ControlsBindingController:\n").apply { + append(" refreshing=${refreshing.get()}\n") + append(" currentUser=$currentUser\n") + append(" Providers:\n") + synchronized(componentMap) { + componentMap.values.forEach { + append(" $it\n") + } + } + }.toString() } private abstract inner class CallbackRunnable(val token: IBinder) : Runnable { @@ -183,6 +220,10 @@ open class ControlsBindingControllerImpl @Inject constructor( Log.e(TAG, "No provider found for token:$token") return } + if (provider.user != currentUser) { + Log.e(TAG, "User ${provider.user} is not current user") + return + } synchronized(componentMap) { if (token !in tokenMap.keys) { Log.e(TAG, "Provider for token:$token does not exist anymore") @@ -192,7 +233,7 @@ open class ControlsBindingControllerImpl @Inject constructor( provider.lastLoadCallback?.invoke(list) ?: run { Log.w(TAG, "Null callback") } - provider.maybeUnbindAndRemoveCallback() + provider.unbindService() } } @@ -204,6 +245,10 @@ open class ControlsBindingControllerImpl @Inject constructor( if (!refreshing.get()) { Log.d(TAG, "onRefresh outside of window from:${provider?.componentName}") } + if (provider?.user != currentUser) { + Log.e(TAG, "User ${provider?.user} is not current user") + return + } provider?.let { lazyController.get().refreshStatus(it.componentName, control) } @@ -229,7 +274,7 @@ open class ControlsBindingControllerImpl @Inject constructor( ) : CallbackRunnable(token) { override fun run() { provider?.let { - Log.i(TAG, "onComplete receive from '${provider?.componentName}'") + Log.i(TAG, "onComplete receive from '${provider.componentName}'") } } } @@ -240,7 +285,7 @@ open class ControlsBindingControllerImpl @Inject constructor( ) : CallbackRunnable(token) { override fun run() { provider?.let { - Log.e(TAG, "onError receive from '${provider?.componentName}': $error") + Log.e(TAG, "onError receive from '${provider.componentName}': $error") } } } @@ -251,9 +296,15 @@ open class ControlsBindingControllerImpl @Inject constructor( @ControlAction.ResponseResult val response: Int ) : CallbackRunnable(token) { override fun run() { + if (provider?.user != currentUser) { + Log.e(TAG, "User ${provider?.user} is not current user") + return + } provider?.let { lazyController.get().onActionResponse(it.componentName, controlId, response) } } } } + +private data class Key(val component: ComponentName, val user: UserHandle)
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index e098faa00d03..b02de4500043 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -20,8 +20,9 @@ import android.content.ComponentName import android.service.controls.Control import android.service.controls.actions.ControlAction import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.UserAwareController -interface ControlsController { +interface ControlsController : UserAwareController { val available: Boolean fun getFavoriteControls(): List<ControlInfo> diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index d5b5b5f0442e..6ff1cf8474d3 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -17,10 +17,13 @@ package com.android.systemui.controls.controller import android.app.PendingIntent +import android.content.BroadcastReceiver import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.os.Environment +import android.os.UserHandle import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.ControlAction @@ -29,14 +32,17 @@ import android.util.Log import com.android.internal.annotations.GuardedBy import com.android.systemui.DumpController import com.android.systemui.Dumpable +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.management.ControlsFavoritingActivity +import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.concurrency.DelayableExecutor import java.io.FileDescriptor import java.io.PrintWriter import java.util.Optional +import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton @@ -46,35 +52,101 @@ class ControlsControllerImpl @Inject constructor ( @Background private val executor: DelayableExecutor, private val uiController: ControlsUiController, private val bindingController: ControlsBindingController, - private val optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>, + private val listingController: ControlsListingController, + broadcastDispatcher: BroadcastDispatcher, + optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>, dumpController: DumpController ) : Dumpable, ControlsController { companion object { private const val TAG = "ControlsControllerImpl" const val CONTROLS_AVAILABLE = "systemui.controls_available" + const val USER_CHANGE_RETRY_DELAY = 500L // ms } - override val available = Settings.Secure.getInt( + // Map of map: ComponentName -> (String -> ControlInfo). + // Only for current user + @GuardedBy("currentFavorites") + private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>() + + private var userChanging = true + override var available = Settings.Secure.getInt( context.contentResolver, CONTROLS_AVAILABLE, 0) != 0 - val persistenceWrapper = optionalWrapper.orElseGet { + private set + + private var currentUser = context.user + override val currentUserId + get() = currentUser.identifier + + private val persistenceWrapper = optionalWrapper.orElseGet { ControlsFavoritePersistenceWrapper( Environment.buildPath( - context.filesDir, - ControlsFavoritePersistenceWrapper.FILE_NAME), + context.filesDir, + ControlsFavoritePersistenceWrapper.FILE_NAME + ), executor ) } - // Map of map: ComponentName -> (String -> ControlInfo) - @GuardedBy("currentFavorites") - private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>() + private fun setValuesForUser(newUser: UserHandle) { + Log.d(TAG, "Changing to user: $newUser") + currentUser = newUser + val userContext = context.createContextAsUser(currentUser, 0) + val fileName = Environment.buildPath( + userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME) + persistenceWrapper.changeFile(fileName) + available = Settings.Secure.getIntForUser( + context.contentResolver, CONTROLS_AVAILABLE, 0) != 0 + synchronized(currentFavorites) { + currentFavorites.clear() + } + if (available) { + loadFavorites() + } + bindingController.changeUser(newUser) + listingController.changeUser(newUser) + userChanging = false + } + + private val userSwitchReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_USER_SWITCHED) { + userChanging = true + val newUser = + UserHandle.of(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, sendingUserId)) + if (currentUser == newUser) { + userChanging = false + return + } + setValuesForUser(newUser) + } + } + } init { + dumpController.registerDumpable(this) if (available) { - dumpController.registerDumpable(this) loadFavorites() } + userChanging = false + broadcastDispatcher.registerReceiver( + userSwitchReceiver, + IntentFilter(Intent.ACTION_USER_SWITCHED), + executor, + UserHandle.ALL + ) + } + + private fun confirmAvailability(): Boolean { + if (userChanging) { + Log.w(TAG, "Controls not available while user is changing") + return false + } + if (!available) { + Log.d(TAG, "Controls not available") + return false + } + return true } private fun loadFavorites() { @@ -91,8 +163,18 @@ class ControlsControllerImpl @Inject constructor ( componentName: ComponentName, callback: (List<ControlStatus>) -> Unit ) { - if (!available) { - Log.d(TAG, "Controls not available") + if (!confirmAvailability()) { + if (userChanging) { + // Try again later, userChanging should not last forever. If so, we have bigger + // problems + executor.executeDelayed( + { loadForComponent(componentName, callback) }, + USER_CHANGE_RETRY_DELAY, + TimeUnit.MILLISECONDS + ) + } else { + callback(emptyList()) + } return } bindingController.bindAndLoad(componentName) { @@ -158,10 +240,7 @@ class ControlsControllerImpl @Inject constructor ( } override fun subscribeToFavorites() { - if (!available) { - Log.d(TAG, "Controls not available") - return - } + if (!confirmAvailability()) return // Make a copy of the favorites list val favorites = synchronized(currentFavorites) { currentFavorites.flatMap { it.value.values.toList() } @@ -170,18 +249,12 @@ class ControlsControllerImpl @Inject constructor ( } override fun unsubscribe() { - if (!available) { - Log.d(TAG, "Controls not available") - return - } + if (!confirmAvailability()) return bindingController.unsubscribe() } override fun changeFavoriteStatus(controlInfo: ControlInfo, state: Boolean) { - if (!available) { - Log.d(TAG, "Controls not available") - return - } + if (!confirmAvailability()) return var changed = false val listOfControls = synchronized(currentFavorites) { if (state) { @@ -211,7 +284,7 @@ class ControlsControllerImpl @Inject constructor ( } override fun refreshStatus(componentName: ComponentName, control: Control) { - if (!available) { + if (!confirmAvailability()) { Log.d(TAG, "Controls not available") return } @@ -227,28 +300,24 @@ class ControlsControllerImpl @Inject constructor ( } override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) { - if (!available) { - Log.d(TAG, "Controls not available") - return - } + if (!confirmAvailability()) return uiController.onActionResponse(componentName, controlId, response) } override fun getFavoriteControls(): List<ControlInfo> { - if (!available) { - Log.d(TAG, "Controls not available") - return emptyList() - } + if (!confirmAvailability()) return emptyList() synchronized(currentFavorites) { return favoritesAsListLocked() } } override fun action(controlInfo: ControlInfo, action: ControlAction) { + if (!confirmAvailability()) return bindingController.action(controlInfo, action) } override fun clearFavorites() { + if (!confirmAvailability()) return val changed = synchronized(currentFavorites) { currentFavorites.isNotEmpty().also { currentFavorites.clear() @@ -261,6 +330,9 @@ class ControlsControllerImpl @Inject constructor ( override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { pw.println("ControlsController state:") + pw.println(" Available: $available") + pw.println(" Changing users: $userChanging") + pw.println(" Current user: ${currentUser.identifier}") pw.println(" Favorites:") synchronized(currentFavorites) { currentFavorites.forEach { @@ -269,5 +341,6 @@ class ControlsControllerImpl @Inject constructor ( } } } + pw.println(bindingController.toString()) } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt index 6f2d71fd0f59..7d1df14bbf1b 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt @@ -16,7 +16,6 @@ package com.android.systemui.controls.controller -import android.app.ActivityManager import android.content.ComponentName import android.util.AtomicFile import android.util.Log @@ -32,8 +31,8 @@ import java.io.FileNotFoundException import java.io.IOException class ControlsFavoritePersistenceWrapper( - val file: File, - val executor: DelayableExecutor + private var file: File, + private var executor: DelayableExecutor ) { companion object { @@ -47,11 +46,13 @@ class ControlsFavoritePersistenceWrapper( private const val TAG_TYPE = "type" } - val currentUser: Int - get() = ActivityManager.getCurrentUser() + fun changeFile(fileName: File) { + file = fileName + } fun storeFavorites(list: List<ControlInfo>) { executor.execute { + Log.d(TAG, "Saving data to file: $file") val atomicFile = AtomicFile(file) val writer = try { atomicFile.startWrite() @@ -98,6 +99,7 @@ class ControlsFavoritePersistenceWrapper( return emptyList() } try { + Log.d(TAG, "Reading data from file: $file") val parser = Xml.newPullParser() parser.setInput(reader, null) return parseXml(parser) @@ -111,7 +113,7 @@ class ControlsFavoritePersistenceWrapper( } private fun parseXml(parser: XmlPullParser): List<ControlInfo> { - var type: Int = 0 + var type = 0 val infos = mutableListOf<ControlInfo>() while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { @@ -123,9 +125,9 @@ class ControlsFavoritePersistenceWrapper( parser.getAttributeValue(null, TAG_COMPONENT)) val id = parser.getAttributeValue(null, TAG_ID) val title = parser.getAttributeValue(null, TAG_TITLE) - val type = parser.getAttributeValue(null, TAG_TYPE)?.toInt() - if (component != null && id != null && title != null && type != null) { - infos.add(ControlInfo(component, id, title, type)) + val deviceType = parser.getAttributeValue(null, TAG_TYPE)?.toInt() + if (component != null && id != null && title != null && deviceType != null) { + infos.add(ControlInfo(component, id, title, deviceType)) } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 99aa3601ba30..b4bd82c84e1a 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -24,6 +24,7 @@ import android.os.Binder import android.os.Bundle import android.os.IBinder import android.os.RemoteException +import android.os.UserHandle import android.service.controls.Control import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE import android.service.controls.ControlsProviderService.CALLBACK_TOKEN @@ -46,6 +47,7 @@ class ControlsProviderLifecycleManager( private val loadCallbackService: IControlsLoadCallback.Stub, private val actionCallbackService: IControlsActionCallback.Stub, private val subscriberService: IControlsSubscriber.Stub, + val user: UserHandle, val componentName: ComponentName ) : IBinder.DeathRecipient { @@ -54,9 +56,7 @@ class ControlsProviderLifecycleManager( val token: IBinder = Binder() @GuardedBy("subscriptions") private val subscriptions = mutableListOf<IControlsSubscription>() - private var unbindImmediate = false private var requiresBound = false - private var isBound = false @GuardedBy("queuedMessages") private val queuedMessages: MutableSet<Message> = ArraySet() private var wrapper: ServiceWrapper? = null @@ -96,30 +96,22 @@ class ControlsProviderLifecycleManager( } bindTryCount++ try { - isBound = context.bindService(intent, serviceConnection, BIND_FLAGS) + context.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user) } catch (e: SecurityException) { Log.e(TAG, "Failed to bind to service", e) - isBound = false } } else { if (DEBUG) { Log.d(TAG, "Unbinding service $intent") } bindTryCount = 0 - wrapper = null - if (isBound) { + wrapper?.run { context.unbindService(serviceConnection) - isBound = false } + wrapper = null } } - fun bindPermanently() { - unbindImmediate = false - unqueueMessage(Message.Unbind) - bindService(true) - } - private val serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName, service: IBinder) { if (DEBUG) Log.d(TAG, "onServiceConnected $name") @@ -133,7 +125,7 @@ class ControlsProviderLifecycleManager( override fun onServiceDisconnected(name: ComponentName?) { if (DEBUG) Log.d(TAG, "onServiceDisconnected $name") - isBound = false + wrapper = null bindService(false) } } @@ -152,7 +144,9 @@ class ControlsProviderLifecycleManager( load() } queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run { - subscribe(this) + if (this.isNotEmpty()) { + subscribe(this) + } } queue.filter { it is Message.Action }.forEach { val msg = it as Message.Action @@ -193,6 +187,15 @@ class ControlsProviderLifecycleManager( } } + private fun invokeOrQueue(f: () -> Unit, msg: Message) { + wrapper?.run { + f() + } ?: run { + queueMessage(msg) + bindService(true) + } + } + fun maybeBindAndLoad(callback: LoadCallback) { unqueueMessage(Message.Unbind) lastLoadCallback = callback @@ -201,22 +204,12 @@ class ControlsProviderLifecycleManager( Log.d(TAG, "Timeout waiting onLoad for $componentName") loadCallbackService.accept(token, emptyList()) }, LOAD_TIMEOUT, TimeUnit.MILLISECONDS) - if (isBound) { - load() - } else { - queueMessage(Message.Load) - unbindImmediate = true - bindService(true) - } + + invokeOrQueue(::load, Message.Load) } fun maybeBindAndSubscribe(controlIds: List<String>) { - if (isBound) { - subscribe(controlIds) - } else { - queueMessage(Message.Subscribe(controlIds)) - bindService(true) - } + invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds)) } private fun subscribe(controlIds: List<String>) { @@ -230,12 +223,7 @@ class ControlsProviderLifecycleManager( } fun maybeBindAndSendAction(controlId: String, action: ControlAction) { - if (isBound) { - action(controlId, action) - } else { - queueMessage(Message.Action(controlId, action)) - bindService(true) - } + invokeOrQueue({ action(controlId, action) }, Message.Action(controlId, action)) } private fun action(controlId: String, action: ControlAction) { @@ -272,18 +260,25 @@ class ControlsProviderLifecycleManager( } } - fun maybeUnbindAndRemoveCallback() { + fun bindService() { + unqueueMessage(Message.Unbind) + bindService(true) + } + + fun unbindService() { lastLoadCallback = null onLoadCanceller?.run() onLoadCanceller = null - if (unbindImmediate) { - bindService(false) - } + + bindService(false) } - fun unbindService() { - unbindImmediate = true - maybeUnbindAndRemoveCallback() + override fun toString(): String { + return StringBuilder("ControlsProviderLifecycleManager(").apply { + append("component=$componentName") + append(", user=$user") + append(")") + }.toString() } sealed class Message { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt index d62bb4def3aa..22c69086cf8c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt @@ -23,6 +23,7 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.android.settingslib.widget.CandidateInfo import com.android.systemui.R diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index 01c4fef67fd4..7ee4fd5b059e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -22,15 +22,18 @@ import android.os.Bundle import android.view.LayoutInflater import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.settings.CurrentUserTracker import java.util.concurrent.Executor import javax.inject.Inject class ControlsFavoritingActivity @Inject constructor( @Main private val executor: Executor, - private val controller: ControlsControllerImpl + private val controller: ControlsControllerImpl, + broadcastDispatcher: BroadcastDispatcher ) : Activity() { companion object { @@ -42,11 +45,24 @@ class ControlsFavoritingActivity @Inject constructor( private lateinit var recyclerView: RecyclerView private lateinit var adapter: ControlAdapter + private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { + private val startingUser = controller.currentUserId + + override fun onUserSwitched(newUserId: Int) { + if (newUserId != startingUser) { + stopTracking() + finish() + } + } + } + + private var component: ComponentName? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val app = intent.getCharSequenceExtra(EXTRA_APP) - val component = intent.getParcelableExtra<ComponentName>(EXTRA_COMPONENT) + component = intent.getParcelableExtra<ComponentName>(EXTRA_COMPONENT) // If we have no component name, there's not much we can do. val callback = component?.let { @@ -68,6 +84,11 @@ class ControlsFavoritingActivity @Inject constructor( } setContentView(recyclerView) + currentUserTracker.startTracking() + } + + override fun onResume() { + super.onResume() component?.let { controller.loadForComponent(it) { executor.execute { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt index 09e0ce9fea8d..34db684022fb 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt @@ -18,14 +18,17 @@ package com.android.systemui.controls.management import android.content.ComponentName import com.android.settingslib.widget.CandidateInfo +import com.android.systemui.controls.UserAwareController import com.android.systemui.statusbar.policy.CallbackController interface ControlsListingController : - CallbackController<ControlsListingController.ControlsListingCallback> { + CallbackController<ControlsListingController.ControlsListingCallback>, + UserAwareController { fun getCurrentServices(): List<CandidateInfo> fun getAppLabel(name: ComponentName): CharSequence? = "" + @FunctionalInterface interface ControlsListingCallback { fun onServicesUpdated(list: List<CandidateInfo>) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt index 3949c5929a85..882382cc4ade 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt @@ -19,6 +19,7 @@ package com.android.systemui.controls.management import android.content.ComponentName import android.content.Context import android.content.pm.ServiceInfo +import android.os.UserHandle import android.service.controls.ControlsProviderService import android.util.Log import com.android.internal.annotations.VisibleForTesting @@ -31,6 +32,16 @@ import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton +private fun createServiceListing(context: Context): ServiceListing { + return ServiceListing.Builder(context).apply { + setIntentAction(ControlsProviderService.SERVICE_CONTROLS) + setPermission("android.permission.BIND_CONTROLS") + setNoun("Controls Provider") + setSetting("controls_providers") + setTag("controls_providers") + }.build() +} + /** * Provides a listing of components to be used as ControlsServiceProvider. * @@ -43,41 +54,55 @@ import javax.inject.Singleton class ControlsListingControllerImpl @VisibleForTesting constructor( private val context: Context, @Background private val backgroundExecutor: Executor, - private val serviceListing: ServiceListing + private val serviceListingBuilder: (Context) -> ServiceListing ) : ControlsListingController { @Inject constructor(context: Context, executor: Executor): this( context, executor, - ServiceListing.Builder(context) - .setIntentAction(ControlsProviderService.SERVICE_CONTROLS) - .setPermission("android.permission.BIND_CONTROLS") - .setNoun("Controls Provider") - .setSetting("controls_providers") - .setTag("controls_providers") - .build() + ::createServiceListing ) + private var serviceListing = serviceListingBuilder(context) + companion object { private const val TAG = "ControlsListingControllerImpl" } private var availableServices = emptyList<ServiceInfo>() - init { - serviceListing.addCallback { - Log.d(TAG, "ServiceConfig reloaded") - availableServices = it.toList() - - backgroundExecutor.execute { - callbacks.forEach { - it.onServicesUpdated(getCurrentServices()) - } + override var currentUserId = context.userId + private set + + private val serviceListingCallback = ServiceListing.Callback { + Log.d(TAG, "ServiceConfig reloaded") + availableServices = it.toList() + + backgroundExecutor.execute { + callbacks.forEach { + it.onServicesUpdated(getCurrentServices()) } } } + init { + serviceListing.addCallback(serviceListingCallback) + } + + override fun changeUser(newUser: UserHandle) { + backgroundExecutor.execute { + callbacks.clear() + availableServices = emptyList() + serviceListing.setListening(false) + serviceListing.removeCallback(serviceListingCallback) + currentUserId = newUser.identifier + val contextForUser = context.createContextAsUser(newUser, 0) + serviceListing = serviceListingBuilder(contextForUser) + serviceListing.addCallback(serviceListingCallback) + } + } + // All operations in background thread private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>() @@ -91,6 +116,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor( */ override fun addCallback(listener: ControlsListingController.ControlsListingCallback) { backgroundExecutor.execute { + Log.d(TAG, "Subscribing callback") callbacks.add(listener) if (callbacks.size == 1) { serviceListing.setListening(true) @@ -108,6 +134,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor( */ override fun removeCallback(listener: ControlsListingController.ControlsListingCallback) { backgroundExecutor.execute { + Log.d(TAG, "Unsubscribing callback") callbacks.remove(listener) if (callbacks.size == 0) { serviceListing.setListening(false) diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index 69af516b4ac9..5ff949c98806 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -22,7 +22,10 @@ import android.os.Bundle import android.view.LayoutInflater import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.settings.CurrentUserTracker import com.android.systemui.util.LifecycleActivity import java.util.concurrent.Executor import javax.inject.Inject @@ -32,7 +35,9 @@ import javax.inject.Inject */ class ControlsProviderSelectorActivity @Inject constructor( @Main private val executor: Executor, - private val listingController: ControlsListingController + @Background private val backExecutor: Executor, + private val listingController: ControlsListingController, + broadcastDispatcher: BroadcastDispatcher ) : LifecycleActivity() { companion object { @@ -40,6 +45,16 @@ class ControlsProviderSelectorActivity @Inject constructor( } private lateinit var recyclerView: RecyclerView + private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { + private val startingUser = listingController.currentUserId + + override fun onUserSwitched(newUserId: Int) { + if (newUserId != startingUser) { + stopTracking() + finish() + } + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -50,6 +65,7 @@ class ControlsProviderSelectorActivity @Inject constructor( recyclerView.layoutManager = LinearLayoutManager(applicationContext) setContentView(recyclerView) + currentUserTracker.startTracking() } /** @@ -57,13 +73,17 @@ class ControlsProviderSelectorActivity @Inject constructor( * @param component a component name for a [ControlsProviderService] */ fun launchFavoritingActivity(component: ComponentName?) { - component?.let { - val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java).apply { - putExtra(ControlsFavoritingActivity.EXTRA_APP, listingController.getAppLabel(it)) - putExtra(ControlsFavoritingActivity.EXTRA_COMPONENT, it) - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP + backExecutor.execute { + component?.let { + val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java) + .apply { + putExtra(ControlsFavoritingActivity.EXTRA_APP, + listingController.getAppLabel(it)) + putExtra(ControlsFavoritingActivity.EXTRA_COMPONENT, it) + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP + } + startActivity(intent) } - startActivity(intent) } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt new file mode 100644 index 000000000000..44f3fbc58eaf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt @@ -0,0 +1,21 @@ +/* + * 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.controls.ui + +interface Behavior { + fun apply(cvh: ControlViewHolder, cws: ControlWithState) +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 81b5f3698567..5519e32d6c10 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -17,22 +17,17 @@ package com.android.systemui.controls.ui import android.content.Context +import android.content.Intent import android.graphics.drawable.ClipDrawable -import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon import android.graphics.drawable.LayerDrawable import android.service.controls.Control -import android.service.controls.DeviceTypes -import android.service.controls.actions.BooleanAction import android.service.controls.actions.ControlAction -import android.service.controls.actions.FloatAction import android.service.controls.templates.ControlTemplate -import android.service.controls.templates.RangeTemplate +import android.service.controls.templates.TemperatureControlTemplate import android.service.controls.templates.ToggleRangeTemplate import android.service.controls.templates.ToggleTemplate -import android.util.TypedValue -import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -41,8 +36,8 @@ import android.widget.TextView import com.android.systemui.controls.controller.ControlsController import com.android.systemui.R -private const val MIN_LEVEL = 0 -private const val MAX_LEVEL = 10000 +public const val MIN_LEVEL = 0 +public const val MAX_LEVEL = 10000 class ControlViewHolder( val layout: ViewGroup, @@ -78,6 +73,16 @@ class ControlViewHolder( Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE) } + cws.control?.let { c -> + layout.setOnLongClickListener(View.OnLongClickListener() { + val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + context.sendBroadcast(closeDialog) + + c.getAppIntent().send() + true + }) + } + findBehavior(status, template).apply(this, cws) } @@ -88,13 +93,14 @@ class ControlViewHolder( private fun findBehavior(status: Int, template: ControlTemplate): Behavior { return when { status == Control.STATUS_UNKNOWN -> UnknownBehavior() - template is ToggleTemplate -> ToggleTemplateBehavior() - template is ToggleRangeTemplate -> ToggleRangeTemplateBehavior() + template is ToggleTemplate -> ToggleBehavior() + template is ToggleRangeTemplate -> ToggleRangeBehavior() + template is TemperatureControlTemplate -> TemperatureControlBehavior() else -> { object : Behavior { override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { cvh.status.setText(cws.control?.getStatusText()) - cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) + cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false)) } } } @@ -118,283 +124,3 @@ class ControlViewHolder( icon.setEnabled(enabled) } } - -private interface Behavior { - fun apply(cvh: ControlViewHolder, cws: ControlWithState) - - fun findRenderInfo(deviceType: Int, isActive: Boolean): RenderInfo = - deviceRenderMap.getOrDefault(deviceType, unknownDeviceMap).getValue(isActive) -} - -private class UnknownBehavior : Behavior { - override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { - cvh.status.setText("Loading...") - cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) - } -} - -private class ToggleRangeTemplateBehavior : Behavior { - lateinit var clipLayer: Drawable - lateinit var template: ToggleRangeTemplate - lateinit var control: Control - lateinit var cvh: ControlViewHolder - lateinit var rangeTemplate: RangeTemplate - lateinit var statusExtra: TextView - lateinit var status: TextView - lateinit var context: Context - - override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { - this.control = cws.control!! - this.cvh = cvh - - statusExtra = cvh.statusExtra - status = cvh.status - - status.setText(control.getStatusText()) - - context = status.getContext() - - cvh.layout.setOnTouchListener(ToggleRangeTouchListener()) - - val ld = cvh.layout.getBackground() as LayerDrawable - clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) - - template = control.getControlTemplate() as ToggleRangeTemplate - rangeTemplate = template.getRange() - - val checked = template.isChecked() - val deviceType = control.getDeviceType() - - updateRange((rangeTemplate.getCurrentValue() / 100.0f), checked) - - cvh.setEnabled(checked) - cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) - } - - fun toggle() { - cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) - - val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL - clipLayer.setLevel(nextLevel) - } - - fun beginUpdateRange() { - status.setVisibility(View.GONE) - statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() - .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) - } - - fun updateRange(f: Float, checked: Boolean) { - clipLayer.setLevel(if (checked) (MAX_LEVEL * f).toInt() else MIN_LEVEL) - - if (checked && f < 100.0f && f > 0.0f) { - statusExtra.setText("" + (f * 100.0).toInt() + "%") - statusExtra.setVisibility(View.VISIBLE) - } else { - statusExtra.setText("") - statusExtra.setVisibility(View.GONE) - } - } - - fun endUpdateRange(f: Float) { - statusExtra.setText(" - " + (f * 100.0).toInt() + "%") - - val newValue = rangeTemplate.getMinValue() + - (f * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())) - - statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() - .getDimensionPixelSize(R.dimen.control_status_normal).toFloat()) - status.setVisibility(View.VISIBLE) - - cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(newValue))) - } - - fun findNearestStep(value: Float): Float { - var minDiff = 1000f - - var f = rangeTemplate.getMinValue() - while (f <= rangeTemplate.getMaxValue()) { - val currentDiff = Math.abs(value - f) - if (currentDiff < minDiff) { - minDiff = currentDiff - } else { - return f - rangeTemplate.getStepValue() - } - - f += rangeTemplate.getStepValue() - } - - return rangeTemplate.getMaxValue() - } - - inner class ToggleRangeTouchListener() : View.OnTouchListener { - private var initialTouchX: Float = 0.0f - private var initialTouchY: Float = 0.0f - private var isDragging: Boolean = false - private val minDragDiff = 20 - - override fun onTouch(v: View, e: MotionEvent): Boolean { - when (e.getActionMasked()) { - MotionEvent.ACTION_DOWN -> setupTouch(e) - MotionEvent.ACTION_MOVE -> detectDrag(v, e) - MotionEvent.ACTION_UP -> endTouch(v, e) - } - - return true - } - - private fun setupTouch(e: MotionEvent) { - initialTouchX = e.getX() - initialTouchY = e.getY() - } - - private fun detectDrag(v: View, e: MotionEvent) { - val xDiff = Math.abs(e.getX() - initialTouchX) - val yDiff = Math.abs(e.getY() - initialTouchY) - - if (xDiff < minDragDiff) { - isDragging = false - } else { - if (!isDragging) { - this@ToggleRangeTemplateBehavior.beginUpdateRange() - } - v.getParent().requestDisallowInterceptTouchEvent(true) - isDragging = true - if (yDiff > xDiff) { - endTouch(v, e) - } else { - val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) - this@ToggleRangeTemplateBehavior.updateRange(percent, true) - } - } - } - - private fun endTouch(v: View, e: MotionEvent) { - if (!isDragging) { - this@ToggleRangeTemplateBehavior.toggle() - } else { - val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) - this@ToggleRangeTemplateBehavior.endUpdateRange(percent) - } - - initialTouchX = 0.0f - initialTouchY = 0.0f - isDragging = false - } - } -} - -private class ToggleTemplateBehavior : Behavior { - lateinit var clipLayer: Drawable - lateinit var template: ToggleTemplate - lateinit var control: Control - lateinit var cvh: ControlViewHolder - lateinit var context: Context - lateinit var status: TextView - - override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { - this.control = cws.control!! - this.cvh = cvh - status = cvh.status - - status.setText(control.getStatusText()) - - cvh.layout.setOnClickListener(View.OnClickListener() { toggle() }) - - val ld = cvh.layout.getBackground() as LayerDrawable - clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) - - template = control.getControlTemplate() as ToggleTemplate - - val checked = template.isChecked() - val deviceType = control.getDeviceType() - - clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL) - cvh.setEnabled(checked) - cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) - } - - fun toggle() { - cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) - - val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL - clipLayer.setLevel(nextLevel) - } -} - -internal data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) - -private val unknownDeviceMap = mapOf( - false to RenderInfo( - R.drawable.ic_light_off_gm2_24px, - R.color.unknown_foreground, - R.color.unknown_foreground), - true to RenderInfo( - R.drawable.ic_lightbulb_outline_gm2_24px, - R.color.unknown_foreground, - R.color.unknown_foreground) -) - -private val deviceRenderMap = mapOf<Int, Map<Boolean, RenderInfo>>( - DeviceTypes.TYPE_UNKNOWN to unknownDeviceMap, - DeviceTypes.TYPE_LIGHT to mapOf( - false to RenderInfo( - R.drawable.ic_light_off_gm2_24px, - R.color.light_foreground, - R.color.light_background), - true to RenderInfo( - R.drawable.ic_lightbulb_outline_gm2_24px, - R.color.light_foreground, - R.color.light_background) - ), - DeviceTypes.TYPE_THERMOSTAT to mapOf( - false to RenderInfo( - R.drawable.ic_device_thermostat_gm2_24px, - R.color.light_foreground, - R.color.light_background), - true to RenderInfo( - R.drawable.ic_device_thermostat_gm2_24px, - R.color.light_foreground, - R.color.light_background) - ), - DeviceTypes.TYPE_CAMERA to mapOf( - false to RenderInfo( - R.drawable.ic_videocam_gm2_24px, - R.color.light_foreground, - R.color.light_background), - true to RenderInfo( - R.drawable.ic_videocam_gm2_24px, - R.color.light_foreground, - R.color.light_background) - ), - DeviceTypes.TYPE_LOCK to mapOf( - false to RenderInfo( - R.drawable.ic_lock_open_gm2_24px, - R.color.lock_foreground, - R.color.lock_background), - true to RenderInfo( - R.drawable.ic_lock_gm2_24px, - R.color.lock_foreground, - R.color.lock_background) - ), - DeviceTypes.TYPE_SWITCH to mapOf( - false to RenderInfo( - R.drawable.ic_switches_gm2_24px, - R.color.lock_foreground, - R.color.lock_background), - true to RenderInfo( - R.drawable.ic_switches_gm2_24px, - R.color.lock_foreground, - R.color.lock_background) - ), - DeviceTypes.TYPE_OUTLET to mapOf( - false to RenderInfo( - R.drawable.ic_power_off_gm2_24px, - R.color.lock_foreground, - R.color.lock_background), - true to RenderInfo( - R.drawable.ic_power_gm2_24px, - R.color.lock_foreground, - R.color.lock_background) - ) -) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 40a93d69fef4..a777faf57fce 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -138,7 +138,10 @@ class ControlsUiControllerImpl @Inject constructor ( val serviceIntent = Intent() serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock", "com.android.systemui.home.mock.AuthService")) - context.bindService(serviceIntent, tokenProviderConnection!!, Context.BIND_AUTO_CREATE) + if (!context.bindService(serviceIntent, tokenProviderConnection!!, + Context.BIND_AUTO_CREATE)) { + controlsController.get().subscribeToFavorites() + } } private fun showInitialSetupView() { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt new file mode 100644 index 000000000000..24c8020529ff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt @@ -0,0 +1,117 @@ +/* + * 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.controls.ui + +import android.service.controls.DeviceTypes +import android.service.controls.templates.TemperatureControlTemplate + +import com.android.systemui.R + +data class IconState(val disabledResourceId: Int, val enabledResourceId: Int) { + operator fun get(state: Boolean): Int { + return if (state) { + enabledResourceId + } else { + disabledResourceId + } + } +} + +data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) { + + companion object { + fun lookup(deviceType: Int, enabled: Boolean): RenderInfo { + val iconState = deviceIconMap.getValue(deviceType) + val (fg, bg) = deviceColorMap.getValue(deviceType) + return RenderInfo(iconState[enabled], fg, bg) + } + + fun lookup(deviceType: Int, offset: Int, enabled: Boolean): RenderInfo { + val key = deviceType * BUCKET_SIZE + offset + return lookup(key, enabled) + } + } +} + +private const val BUCKET_SIZE = 1000 +private const val THERMOSTAT_RANGE = DeviceTypes.TYPE_THERMOSTAT * BUCKET_SIZE + +public val deviceColorMap = mapOf<Int, Pair<Int, Int>>( + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to + Pair(R.color.thermo_heat_foreground, R.color.thermo_heat_background), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to + Pair(R.color.thermo_cool_foreground, R.color.thermo_cool_background), + DeviceTypes.TYPE_LIGHT to Pair(R.color.light_foreground, R.color.light_background) +).withDefault { + Pair(R.color.control_foreground, R.color.control_background) +} + +public val deviceIconMap = mapOf<Int, IconState>( + THERMOSTAT_RANGE to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_OFF) to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT_COOL) to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + (THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_ECO) to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + DeviceTypes.TYPE_THERMOSTAT to IconState( + R.drawable.ic_device_thermostat_gm2_24px, + R.drawable.ic_device_thermostat_gm2_24px + ), + DeviceTypes.TYPE_LIGHT to IconState( + R.drawable.ic_light_off_gm2_24px, + R.drawable.ic_lightbulb_outline_gm2_24px + ), + DeviceTypes.TYPE_CAMERA to IconState( + R.drawable.ic_videocam_gm2_24px, + R.drawable.ic_videocam_gm2_24px + ), + DeviceTypes.TYPE_LOCK to IconState( + R.drawable.ic_lock_open_gm2_24px, + R.drawable.ic_lock_gm2_24px + ), + DeviceTypes.TYPE_SWITCH to IconState( + R.drawable.ic_switches_gm2_24px, + R.drawable.ic_switches_gm2_24px + ), + DeviceTypes.TYPE_OUTLET to IconState( + R.drawable.ic_power_off_gm2_24px, + R.drawable.ic_power_gm2_24px + ) +).withDefault { + IconState( + R.drawable.ic_light_off_gm2_24px, + R.drawable.ic_lightbulb_outline_gm2_24px + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt new file mode 100644 index 000000000000..ae0ebbb9e1bb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt @@ -0,0 +1,56 @@ +/* + * 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.controls.ui + +import android.content.Context +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.service.controls.Control +import android.service.controls.templates.TemperatureControlTemplate +import android.widget.TextView + +import com.android.systemui.R + +class TemperatureControlBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var template: TemperatureControlTemplate + lateinit var status: TextView + lateinit var context: Context + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + status = cvh.status + + status.setText(control.getStatusText()) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as TemperatureControlTemplate + + val activeMode = template.getCurrentActiveMode() + val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF + val deviceType = control.getDeviceType() + + clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL) + cvh.setEnabled(enabled) + cvh.applyRenderInfo(RenderInfo.lookup(deviceType, activeMode, enabled)) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt new file mode 100644 index 000000000000..7cd3ab795678 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt @@ -0,0 +1,66 @@ +/* + * 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.controls.ui + +import android.content.Context +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.view.View +import android.widget.TextView +import android.service.controls.Control +import android.service.controls.actions.BooleanAction +import android.service.controls.templates.ToggleTemplate + +import com.android.systemui.R + +class ToggleBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var context: Context + lateinit var status: TextView + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + status = cvh.status + + status.setText(control.getStatusText()) + + cvh.layout.setOnClickListener(View.OnClickListener() { toggle() }) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleTemplate + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL) + cvh.setEnabled(checked) + cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt new file mode 100644 index 000000000000..a6918f50a977 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -0,0 +1,183 @@ +/* + * 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.controls.ui + +import android.content.Context +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.view.MotionEvent +import android.view.View +import android.widget.TextView +import android.service.controls.Control +import android.service.controls.actions.BooleanAction +import android.service.controls.actions.FloatAction +import android.service.controls.templates.RangeTemplate +import android.service.controls.templates.ToggleRangeTemplate +import android.util.TypedValue + +import com.android.systemui.R + +class ToggleRangeBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleRangeTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var rangeTemplate: RangeTemplate + lateinit var statusExtra: TextView + lateinit var status: TextView + lateinit var context: Context + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + + statusExtra = cvh.statusExtra + status = cvh.status + + status.setText(control.getStatusText()) + + context = status.getContext() + + cvh.layout.setOnTouchListener(ToggleRangeTouchListener()) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleRangeTemplate + rangeTemplate = template.getRange() + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + updateRange((rangeTemplate.getCurrentValue() / 100.0f), checked) + + cvh.setEnabled(checked) + cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } + + fun beginUpdateRange() { + status.setVisibility(View.GONE) + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) + } + + fun updateRange(f: Float, checked: Boolean) { + clipLayer.setLevel(if (checked) (MAX_LEVEL * f).toInt() else MIN_LEVEL) + + if (checked && f < 100.0f && f > 0.0f) { + statusExtra.setText("" + (f * 100.0).toInt() + "%") + statusExtra.setVisibility(View.VISIBLE) + } else { + statusExtra.setText("") + statusExtra.setVisibility(View.GONE) + } + } + + fun endUpdateRange(f: Float) { + statusExtra.setText(" - " + (f * 100.0).toInt() + "%") + + val newValue = rangeTemplate.getMinValue() + + (f * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())) + + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_normal).toFloat()) + status.setVisibility(View.VISIBLE) + + cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(newValue))) + } + + fun findNearestStep(value: Float): Float { + var minDiff = 1000f + + var f = rangeTemplate.getMinValue() + while (f <= rangeTemplate.getMaxValue()) { + val currentDiff = Math.abs(value - f) + if (currentDiff < minDiff) { + minDiff = currentDiff + } else { + return f - rangeTemplate.getStepValue() + } + + f += rangeTemplate.getStepValue() + } + + return rangeTemplate.getMaxValue() + } + + inner class ToggleRangeTouchListener() : View.OnTouchListener { + private var initialTouchX: Float = 0.0f + private var initialTouchY: Float = 0.0f + private var isDragging: Boolean = false + private val minDragDiff = 20 + + override fun onTouch(v: View, e: MotionEvent): Boolean { + when (e.getActionMasked()) { + MotionEvent.ACTION_DOWN -> setupTouch(e) + MotionEvent.ACTION_MOVE -> detectDrag(v, e) + MotionEvent.ACTION_UP -> endTouch(v, e) + } + + return true + } + + private fun setupTouch(e: MotionEvent) { + initialTouchX = e.getX() + initialTouchY = e.getY() + } + + private fun detectDrag(v: View, e: MotionEvent) { + val xDiff = Math.abs(e.getX() - initialTouchX) + val yDiff = Math.abs(e.getY() - initialTouchY) + + if (xDiff < minDragDiff) { + isDragging = false + } else { + if (!isDragging) { + this@ToggleRangeBehavior.beginUpdateRange() + } + v.getParent().requestDisallowInterceptTouchEvent(true) + isDragging = true + if (yDiff > xDiff) { + endTouch(v, e) + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeBehavior.updateRange(percent, true) + } + } + } + + private fun endTouch(v: View, e: MotionEvent) { + if (!isDragging) { + this@ToggleRangeBehavior.toggle() + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeBehavior.endUpdateRange(percent) + } + + initialTouchX = 0.0f + initialTouchY = 0.0f + isDragging = false + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt new file mode 100644 index 000000000000..5a6e5b481544 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt @@ -0,0 +1,25 @@ +/* + * 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.controls.ui + +class UnknownBehavior : Behavior { + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + cvh.status.setText("Loading...") + cvh.setEnabled(false) + cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false)) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index f793b3df92a4..7b541991088c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.StatusBarWindowBlurController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.phone.KeyguardLiftController; @@ -64,6 +65,7 @@ import dagger.Provides; AssistModule.class, ConcurrencyModule.class, LogModule.class, + NotificationsModule.class, PeopleHubModule.class, }, subcomponents = {StatusBarComponent.class, NotificationRowComponent.class}) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 43db85bd91ec..6f655bb0b209 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -118,6 +118,7 @@ public class DozeFactory { new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController, mDozeParameters), new DozeDockHandler(config, machine, mDockManager), + new DozeSuppressedHandler(dozeService, config, machine), new DozeAuthRemover(dozeService) }); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 8afdf1aeb023..96ae6c9ec4a2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -266,6 +266,14 @@ public class DozeLog implements Dumpable { mLogger.logSensorTriggered(reason); } + /** + * Appends doze suppressed event to the logs + * @param suppressedState The {@link DozeMachine.State} that was suppressed + */ + public void traceDozeSuppressed(DozeMachine.State suppressedState) { + mLogger.logDozeSuppressed(suppressedState); + } + private class SummaryStats { private int mCount; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index 42decd592071..732745a1158b 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -194,6 +194,14 @@ class DozeLogger @Inject constructor( "Sensor triggered, type=${reasonToString(int1)}" }) } + + fun logDozeSuppressed(state: DozeMachine.State) { + buffer.log(TAG, INFO, { + str1 = state.name + }, { + "Doze state suppressed, state=$str1" + }) + } } private const val TAG = "DozeLog" diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 03c25eee4f6f..6e81d3a11098 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -102,6 +102,10 @@ public class DozeMachine { } } + boolean isAlwaysOn() { + return this == DOZE_AOD || this == DOZE_AOD_DOCKED; + } + int screenState(DozeParameters parameters) { switch (this) { case UNINITIALIZED: @@ -324,6 +328,11 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } + if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT) && requestedState.isAlwaysOn()) { + Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState); + mDozeLog.traceDozeSuppressed(requestedState); + return State.DOZE; + } if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING || mState == State.DOZE_AOD || mState == State.DOZE) && requestedState == State.DOZE_PULSE_DONE) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index 3abeea91cdee..e50f1fb2a3ee 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -18,7 +18,6 @@ package com.android.systemui.doze; import static com.android.systemui.doze.DozeMachine.State.DOZE; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; -import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING; import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE; @@ -90,10 +89,10 @@ public class DozeScreenState implements DozeMachine.Part { } final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState); - final boolean pulseEnding = oldState == DOZE_PULSE_DONE && isAlwaysOnState(newState); + final boolean pulseEnding = oldState == DOZE_PULSE_DONE && newState.isAlwaysOn(); final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE) - && isAlwaysOnState(newState); - final boolean turningOff = (isAlwaysOnState(oldState) && newState == DOZE) + && newState.isAlwaysOn(); + final boolean turningOff = (newState.isAlwaysOn() && newState == DOZE) || (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED); final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED; if (messagePending || justInitialized || pulseEnding || turningOn) { @@ -132,10 +131,6 @@ public class DozeScreenState implements DozeMachine.Part { } } - private boolean isAlwaysOnState(DozeMachine.State state) { - return state == DOZE_AOD || state == DOZE_AOD_DOCKED; - } - private void applyPendingScreenState() { applyScreenState(mPendingScreenState); mPendingScreenState = Display.STATE_UNKNOWN; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java new file mode 100644 index 000000000000..3a5c1a0890f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java @@ -0,0 +1,124 @@ +/* + * 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.doze; + +import static java.util.Objects.requireNonNull; + +import android.app.ActivityManager; +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.display.AmbientDisplayConfiguration; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +/** Handles updating the doze state when doze is suppressed. */ +public final class DozeSuppressedHandler implements DozeMachine.Part { + + private static final String TAG = DozeSuppressedHandler.class.getSimpleName(); + private static final boolean DEBUG = DozeService.DEBUG; + + private final ContentResolver mResolver; + private final AmbientDisplayConfiguration mConfig; + private final DozeMachine mMachine; + private final DozeSuppressedSettingObserver mSettingObserver; + private final Handler mHandler = new Handler(); + + public DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config, + DozeMachine machine) { + this(context, config, machine, null); + } + + @VisibleForTesting + DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config, DozeMachine machine, + DozeSuppressedSettingObserver observer) { + mResolver = context.getContentResolver(); + mConfig = requireNonNull(config); + mMachine = requireNonNull(machine); + if (observer == null) { + mSettingObserver = new DozeSuppressedSettingObserver(mHandler); + } else { + mSettingObserver = observer; + } + } + + @Override + public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { + switch (newState) { + case INITIALIZED: + mSettingObserver.register(); + break; + case FINISH: + mSettingObserver.unregister(); + break; + default: + // no-op + } + } + + /** + * Listens to changes to the DOZE_SUPPRESSED secure setting and updates the doze state + * accordingly. + */ + final class DozeSuppressedSettingObserver extends ContentObserver { + private boolean mRegistered; + + private DozeSuppressedSettingObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (userId != ActivityManager.getCurrentUser()) { + return; + } + final DozeMachine.State nextState; + if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) + && !mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) { + nextState = DozeMachine.State.DOZE_AOD; + } else { + nextState = DozeMachine.State.DOZE; + } + mMachine.requestState(nextState); + } + + void register() { + if (mRegistered) { + return; + } + mResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.SUPPRESS_DOZE), + false, this, UserHandle.USER_CURRENT); + Log.d(TAG, "Register"); + mRegistered = true; + } + + void unregister() { + if (!mRegistered) { + return; + } + mResolver.unregisterContentObserver(this); + Log.d(TAG, "Unregister"); + mRegistered = false; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index b9c056df89a1..305a4c870d91 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -127,6 +127,11 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } + if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) { + runIfNotNull(onPulseSuppressedListener); + mDozeLog.tracePulseDropped("dozeSuppressed"); + return; + } requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, onPulseSuppressedListener); mDozeLog.traceNotificationPulse(); diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index f33c931479ba..45c07a3e4693 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1801,6 +1801,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, void dismissImmediately() { mShowing = false; + if (mControlsUiController != null) mControlsUiController.hide(); dismissPanel(); resetOrientation(); completeDismiss(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt index f66a1ece1868..f710f7fc47e2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt @@ -68,7 +68,7 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil override fun updateResources(): Boolean { with(mContext.resources) { smallTileSize = getDimensionPixelSize(R.dimen.qs_quick_tile_size) - cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2 + cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) cellMarginVertical = getDimensionPixelSize(R.dimen.new_qs_vertical_margin) } requestLayout() diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 1077834e7146..9e3e94ce4186 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -36,7 +36,6 @@ import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; -import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -45,7 +44,6 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.RemoteViews; import android.widget.TextView; import androidx.core.graphics.drawable.RoundedBitmapDrawable; @@ -72,8 +70,6 @@ public class QSMediaPlayer { private View mSeamless; private MediaSession.Token mToken; private MediaController mController; - private int mWidth; - private int mHeight; private int mForegroundColor; private int mBackgroundColor; private ComponentName mRecvComponent; @@ -158,16 +154,11 @@ public class QSMediaPlayer { * * @param context * @param parent - * @param width - * @param height */ - public QSMediaPlayer(Context context, ViewGroup parent, int width, int height) { + public QSMediaPlayer(Context context, ViewGroup parent) { mContext = context; LayoutInflater inflater = LayoutInflater.from(mContext); mMediaNotifView = (LinearLayout) inflater.inflate(R.layout.qs_media_panel, parent, false); - - mWidth = width; - mHeight = height; } public View getView() { @@ -217,27 +208,18 @@ public class QSMediaPlayer { Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif); // Album art - addAlbumArtBackground(mMediaMetadata, bgColor, mWidth, mHeight); + addAlbumArt(mMediaMetadata, bgColor); - // Reuse notification header instead of reimplementing everything - RemoteViews headerRemoteView = builder.makeNotificationHeader(); LinearLayout headerView = mMediaNotifView.findViewById(R.id.header); - View result = headerRemoteView.apply(mContext, headerView); - result.setPadding(0, 0, 0, 0); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, 75); - result.setLayoutParams(lp); - headerView.removeAllViews(); - headerView.addView(result); // App icon - ImageView appIcon = headerView.findViewById(com.android.internal.R.id.icon); + ImageView appIcon = headerView.findViewById(R.id.icon); Drawable iconDrawable = icon.loadDrawable(mContext); iconDrawable.setTint(iconColor); appIcon.setImageDrawable(iconDrawable); // App title - TextView appName = headerView.findViewById(com.android.internal.R.id.app_name_text); + TextView appName = headerView.findViewById(R.id.app_name); String appNameString = builder.loadHeaderAppName(); appName.setText(appNameString); appName.setTextColor(iconColor); @@ -254,25 +236,8 @@ public class QSMediaPlayer { } }); - // Separator - TextView separator = headerView.findViewById(com.android.internal.R.id.header_text_divider); - separator.setTextColor(iconColor); - - // Album name - TextView albumName = headerView.findViewById(com.android.internal.R.id.header_text); - String albumString = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM); - if (TextUtils.isEmpty(albumString)) { - albumName.setVisibility(View.GONE); - separator.setVisibility(View.GONE); - } else { - albumName.setText(albumString); - albumName.setTextColor(iconColor); - albumName.setVisibility(View.VISIBLE); - separator.setVisibility(View.VISIBLE); - } - // Transfer chip - mSeamless = headerView.findViewById(com.android.internal.R.id.media_seamless); + mSeamless = headerView.findViewById(R.id.media_seamless); mSeamless.setVisibility(View.VISIBLE); updateChip(device); ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); @@ -284,13 +249,13 @@ public class QSMediaPlayer { }); // Artist name - TextView artistText = mMediaNotifView.findViewById(R.id.header_title); + TextView artistText = headerView.findViewById(R.id.header_artist); String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST); artistText.setText(artistName); artistText.setTextColor(iconColor); // Song name - TextView titleText = mMediaNotifView.findViewById(R.id.header_text); + TextView titleText = headerView.findViewById(R.id.header_text); String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE); titleText.setText(songName); titleText.setTextColor(iconColor); @@ -363,34 +328,25 @@ public class QSMediaPlayer { return (state.getState() == PlaybackState.STATE_PLAYING); } - private void addAlbumArtBackground(MediaMetadata metadata, int bgColor, int width, int height) { + private void addAlbumArt(MediaMetadata metadata, int bgColor) { Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius); + ImageView albumView = mMediaNotifView.findViewById(R.id.album_art); if (albumArt != null) { Log.d(TAG, "updating album art"); Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true); - Bitmap scaled = scaleBitmap(original, width, height); - Canvas canvas = new Canvas(scaled); - - // Add translucent layer over album art to improve contrast - Paint p = new Paint(); - p.setStyle(Paint.Style.FILL); - p.setColor(bgColor); - p.setAlpha(200); - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), p); - + int albumSize = (int) mContext.getResources().getDimension(R.dimen.qs_media_album_size); + Bitmap scaled = scaleBitmap(original, albumSize, albumSize); RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create( mContext.getResources(), scaled); roundedDrawable.setCornerRadius(radius); - - mMediaNotifView.setBackground(roundedDrawable); + albumView.setImageDrawable(roundedDrawable); } else { Log.e(TAG, "No album art available"); - GradientDrawable rect = new GradientDrawable(); - rect.setCornerRadius(radius); - rect.setColor(bgColor); - mMediaNotifView.setBackground(rect); + albumView.setImageDrawable(null); } + + mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(bgColor)); } private Bitmap scaleBitmap(Bitmap original, int width, int height) { @@ -423,8 +379,8 @@ public class QSMediaPlayer { rect.setStroke(2, mForegroundColor); rect.setColor(mBackgroundColor); - ImageView iconView = mSeamless.findViewById(com.android.internal.R.id.media_seamless_image); - TextView deviceName = mSeamless.findViewById(com.android.internal.R.id.media_seamless_text); + ImageView iconView = mSeamless.findViewById(R.id.media_seamless_image); + TextView deviceName = mSeamless.findViewById(R.id.media_seamless_text); deviceName.setTextColor(fgTintList); if (device != null) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 0fd74547334b..14a117ca40a1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -95,6 +95,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>(); private LocalMediaManager mLocalMediaManager; private MediaDevice mDevice; + private boolean mUpdateCarousel = false; protected boolean mExpanded; protected boolean mListening; @@ -184,7 +185,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne HorizontalScrollView mediaScrollView = (HorizontalScrollView) LayoutInflater.from( mContext).inflate(R.layout.media_carousel, this, false); mMediaCarousel = mediaScrollView.findViewById(R.id.media_carousel); - addView(mediaScrollView); + addView(mediaScrollView, 0); } else { mMediaCarousel = null; } @@ -200,6 +201,23 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mPluginManager = pluginManager; } + @Override + public void onVisibilityAggregated(boolean isVisible) { + super.onVisibilityAggregated(isVisible); + if (!isVisible && mUpdateCarousel) { + for (QSMediaPlayer player : mMediaPlayers) { + if (player.isPlaying()) { + LayoutParams lp = (LayoutParams) player.getView().getLayoutParams(); + mMediaCarousel.removeView(player.getView()); + mMediaCarousel.addView(player.getView(), 0, lp); + ((HorizontalScrollView) mMediaCarousel.getParent()).fullScroll(View.FOCUS_LEFT); + mUpdateCarousel = false; + break; + } + } + } + } + /** * Add or update a player for the associated media session * @param token @@ -237,7 +255,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } - int playerHeight = (int) getResources().getDimension(R.dimen.qs_media_height); int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width); int padding = (int) getResources().getDimension(R.dimen.qs_media_padding); LayoutParams lp = new LayoutParams(playerWidth, ViewGroup.LayoutParams.MATCH_PARENT); @@ -246,8 +263,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (player == null) { Log.d(TAG, "creating new player"); - - player = new QSMediaPlayer(mContext, this, playerWidth, playerHeight); + player = new QSMediaPlayer(mContext, this); if (player.isPlaying()) { mMediaCarousel.addView(player.getView(), 0, lp); // add in front @@ -256,9 +272,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } mMediaPlayers.add(player); } else if (player.isPlaying()) { - // move it to the front - mMediaCarousel.removeView(player.getView()); - mMediaCarousel.addView(player.getView(), 0, lp); + mUpdateCarousel = true; } Log.d(TAG, "setting player session"); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 3fcd1c19370f..476af20b78f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -116,6 +116,7 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic @Override public void onClick(View v) { + if (!hasFooter()) return; mHandler.sendEmptyMessage(H.CLICK); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index cec1cb2fb53b..9018a375c365 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -23,13 +23,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.Icon; import android.media.MediaMetadata; import android.media.session.MediaController; @@ -45,9 +39,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.core.graphics.drawable.RoundedBitmapDrawable; -import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; - import com.android.systemui.R; import java.util.List; @@ -63,7 +54,6 @@ public class QuickQSMediaPlayer { private LinearLayout mMediaNotifView; private MediaSession.Token mToken; private MediaController mController; - private int mBackgroundColor; private int mForegroundColor; private ComponentName mRecvComponent; @@ -142,7 +132,6 @@ public class QuickQSMediaPlayer { View actionsContainer, int[] actionsToShow, PendingIntent contentIntent) { mToken = token; mForegroundColor = iconColor; - mBackgroundColor = bgColor; String oldPackage = ""; if (mController != null) { @@ -185,8 +174,7 @@ public class QuickQSMediaPlayer { } }); - // Album art - addAlbumArtBackground(mMediaMetadata, mBackgroundColor); + mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(bgColor)); // App icon ImageView appIcon = mMediaNotifView.findViewById(R.id.icon); @@ -194,14 +182,8 @@ public class QuickQSMediaPlayer { iconDrawable.setTint(mForegroundColor); appIcon.setImageDrawable(iconDrawable); - // Artist name - TextView appText = mMediaNotifView.findViewById(R.id.header_title); - String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST); - appText.setText(artistName); - appText.setTextColor(mForegroundColor); - // Song name - TextView titleText = mMediaNotifView.findViewById(R.id.header_text); + TextView titleText = mMediaNotifView.findViewById(R.id.header_title); String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE); titleText.setText(songName); titleText.setTextColor(mForegroundColor); @@ -277,54 +259,4 @@ public class QuickQSMediaPlayer { public boolean hasMediaSession() { return mController != null && mController.getPlaybackState() != null; } - - private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) { - Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); - float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius); - Rect bounds = new Rect(); - mMediaNotifView.getBoundsOnScreen(bounds); - int width = bounds.width(); - int height = bounds.height(); - if (albumArt != null && width > 0 && height > 0) { - Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true); - Bitmap scaled = scaleBitmap(original, width, height); - Canvas canvas = new Canvas(scaled); - - // Add translucent layer over album art to improve contrast - Paint p = new Paint(); - p.setStyle(Paint.Style.FILL); - p.setColor(bgColor); - p.setAlpha(200); - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), p); - - RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create( - mContext.getResources(), scaled); - roundedDrawable.setCornerRadius(radius); - - mMediaNotifView.setBackground(roundedDrawable); - } else { - Log.e(TAG, "No album art available"); - GradientDrawable rect = new GradientDrawable(); - rect.setCornerRadius(radius); - rect.setColor(bgColor); - mMediaNotifView.setBackground(rect); - } - } - - private Bitmap scaleBitmap(Bitmap original, int width, int height) { - Bitmap cropped = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(cropped); - - float scale = (float) cropped.getWidth() / (float) original.getWidth(); - float dy = (cropped.getHeight() - original.getHeight() * scale) / 2.0f; - Matrix transformation = new Matrix(); - transformation.postTranslate(0, dy); - transformation.preScale(scale, scale); - - Paint paint = new Paint(); - paint.setFilterBitmap(true); - canvas.drawBitmap(original, transformation, paint); - - return cropped; - } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index b05d4fdf7db7..e9207016eb68 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -85,20 +85,21 @@ public class QuickQSPanel extends QSPanel { mHorizontalLinearLayout.setClipChildren(false); mHorizontalLinearLayout.setClipToPadding(false); + int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing); + mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout); + LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); + lp2.setMarginEnd(marginSize); + lp2.setMarginStart(0); + mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2); + mTileLayout = new DoubleLineTileLayout(context); mMediaTileLayout = mTileLayout; mRegularTileLayout = new HeaderTileLayout(context); LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); - lp.setMarginEnd(10); - lp.setMarginStart(0); + lp.setMarginEnd(0); + lp.setMarginStart(marginSize); mHorizontalLinearLayout.addView((View) mTileLayout, lp); - mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout); - LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); - lp2.setMarginEnd(0); - lp2.setMarginStart(25); - mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2); - sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns); mTileLayout.setListening(mListening); diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 37743ec55517..9f59277c918a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -1,5 +1,7 @@ package com.android.systemui.qs; +import static com.android.systemui.util.Utils.useQsMediaPlayer; + import android.content.Context; import android.content.res.Resources; import android.provider.Settings; @@ -42,7 +44,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout { public TileLayout(Context context, AttributeSet attrs) { super(context, attrs); setFocusableInTouchMode(true); - mLessRows = Settings.System.getInt(context.getContentResolver(), "qs_less_rows", 0) != 0; + mLessRows = (Settings.System.getInt(context.getContentResolver(), "qs_less_rows", 0) != 0) + || useQsMediaPlayer(context); updateResources(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java index de8e6ea4a0cb..7ebebaaef122 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java +++ b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java @@ -70,6 +70,6 @@ public class TriangleShape extends PathShape { @Override public void getOutline(@NonNull Outline outline) { - outline.setConvexPath(mTriangularPath); + outline.setPath(mTriangularPath); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt index 015c32348bb0..269a7a59f1b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt @@ -43,10 +43,10 @@ class BypassHeadsUpNotifier @Inject constructor( private val headsUpManager: HeadsUpManagerPhone, private val notificationLockscreenUserManager: NotificationLockscreenUserManager, private val mediaManager: NotificationMediaManager, + private val entryManager: NotificationEntryManager, tunerService: TunerService ) : StatusBarStateController.StateListener, NotificationMediaManager.MediaListener { - private lateinit var entryManager: NotificationEntryManager private var currentMediaEntry: NotificationEntry? = null private var enabled = true @@ -70,8 +70,7 @@ class BypassHeadsUpNotifier @Inject constructor( }, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING) } - fun setUp(entryManager: NotificationEntryManager) { - this.entryManager = entryManager + fun setUp() { mediaManager.addCallback(this) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java index eaa9d78c08f4..7fe229c26f3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.notification.collection; +import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; + import java.util.Arrays; import java.util.List; @@ -132,8 +135,20 @@ public class ListDumper { .append(" "); } + if (notifEntry.mCancellationReason != REASON_NOT_CANCELED) { + rksb.append("cancellationReason=") + .append(notifEntry.mCancellationReason) + .append(" "); + } + if (notifEntry.hasInflationError()) { - rksb.append("hasInflationError "); + rksb.append("(!)hasInflationError "); + } + + if (notifEntry.getDismissState() != NOT_DISMISSED) { + rksb.append("dismissState=") + .append(notifEntry.getDismissState()) + .append(" "); } String rkString = rksb.toString(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index 8ac4d3008179..3b2fe9441c32 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -35,9 +35,14 @@ import static android.service.notification.NotificationListenerService.REASON_TI import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; + +import static java.util.Objects.requireNonNull; + import android.annotation.IntDef; import android.annotation.MainThread; -import android.annotation.NonNull; import android.annotation.Nullable; import android.os.RemoteException; import android.service.notification.NotificationListenerService.Ranking; @@ -45,6 +50,8 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; +import androidx.annotation.NonNull; + import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.DumpController; import com.android.systemui.Dumpable; @@ -92,8 +99,8 @@ import javax.inject.Singleton; * {@link #addNotificationLifetimeExtender(NotifLifetimeExtender)}). * * Interested parties can register listeners - * ({@link #addCollectionListener(NotifCollectionListener)}) to be informed when notifications are - * added, updated, or removed. + * ({@link #addCollectionListener(NotifCollectionListener)}) to be informed when notifications + * events occur. */ @MainThread @Singleton @@ -172,15 +179,65 @@ public class NotifCollection implements Dumpable { /** * Dismiss a notification on behalf of the user. */ - void dismissNotification( - NotificationEntry entry, - @CancellationReason int reason, - @NonNull DismissedByUserStats stats) { + void dismissNotification(NotificationEntry entry, @NonNull DismissedByUserStats stats) { Assert.isMainThread(); - Objects.requireNonNull(stats); + requireNonNull(stats); checkForReentrantCall(); - removeNotification(entry.getKey(), null, reason, stats); + if (entry != mNotificationSet.get(entry.getKey())) { + throw new IllegalStateException("Invalid entry: " + entry.getKey()); + } + + if (entry.getDismissState() == DISMISSED) { + return; + } + + // Optimistically mark the notification as dismissed -- we'll wait for the signal from + // system server before removing it from our notification set. + entry.setDismissState(DISMISSED); + mLogger.logNotifDismissed(entry.getKey()); + + List<NotificationEntry> canceledEntries = new ArrayList<>(); + + if (isCanceled(entry)) { + canceledEntries.add(entry); + } else { + // Ask system server to remove it for us + try { + mStatusBarService.onNotificationClear( + entry.getSbn().getPackageName(), + entry.getSbn().getTag(), + entry.getSbn().getId(), + entry.getSbn().getUser().getIdentifier(), + entry.getSbn().getKey(), + stats.dismissalSurface, + stats.dismissalSentiment, + stats.notificationVisibility); + } catch (RemoteException e) { + // system process is dead if we're here. + } + + // Also mark any children as dismissed as system server will auto-dismiss them as well + if (entry.getSbn().getNotification().isGroupSummary()) { + for (NotificationEntry otherEntry : mNotificationSet.values()) { + if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey()) + && otherEntry.getDismissState() != DISMISSED) { + otherEntry.setDismissState(PARENT_DISMISSED); + if (isCanceled(otherEntry)) { + canceledEntries.add(otherEntry); + } + } + } + } + } + + // Immediately remove any dismissed notifs that have already been canceled by system server + // (probably due to being lifetime-extended up until this point). + for (NotificationEntry canceledEntry : canceledEntries) { + tryRemoveNotification(canceledEntry); + } + + rebuildList(); } private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { @@ -208,7 +265,15 @@ public class NotifCollection implements Dumpable { Assert.isMainThread(); mLogger.logNotifRemoved(sbn.getKey(), reason); - removeNotification(sbn.getKey(), rankingMap, reason, null); + + final NotificationEntry entry = mNotificationSet.get(sbn.getKey()); + if (entry == null) { + throw new IllegalStateException("No notification to remove with key " + sbn.getKey()); + } + entry.mCancellationReason = reason; + applyRanking(rankingMap); + tryRemoveNotification(entry); + rebuildList(); } private void onNotificationRankingUpdate(RankingMap rankingMap) { @@ -230,6 +295,8 @@ public class NotifCollection implements Dumpable { entry = new NotificationEntry(sbn, ranking); mNotificationSet.put(sbn.getKey(), entry); + dispatchOnEntryInit(entry); + if (rankingMap != null) { applyRanking(rankingMap); } @@ -240,9 +307,12 @@ public class NotifCollection implements Dumpable { // Update to an existing entry mLogger.logNotifUpdated(sbn.getKey()); - // Notification is updated so it is essentially re-added and thus alive again. Don't + cancelLocalDismissal(entry); + + // Notification is updated so it is essentially re-added and thus alive again. Don't // need to keep its lifetime extended. cancelLifetimeExtension(entry); + entry.mCancellationReason = REASON_NOT_CANCELED; entry.setSbn(sbn); if (rankingMap != null) { @@ -253,70 +323,62 @@ public class NotifCollection implements Dumpable { } } - private void removeNotification( - String key, - @Nullable RankingMap rankingMap, - @CancellationReason int reason, - @Nullable DismissedByUserStats dismissedByUserStats) { + /** + * Tries to remove a notification from the notification set. This removal may be blocked by + * lifetime extenders. Does not trigger a rebuild of the list; caller must do that manually. + * + * @return True if the notification was removed, false otherwise. + */ + private boolean tryRemoveNotification(NotificationEntry entry) { + if (mNotificationSet.get(entry.getKey()) != entry) { + throw new IllegalStateException("No notification to remove with key " + entry.getKey()); + } - NotificationEntry entry = mNotificationSet.get(key); - if (entry == null) { - throw new IllegalStateException("No notification to remove with key " + key); + if (!isCanceled(entry)) { + throw new IllegalStateException("Cannot remove notification " + entry.getKey() + + ": has not been marked for removal"); } - entry.mLifetimeExtenders.clear(); - mAmDispatchingToOtherCode = true; - for (NotifLifetimeExtender extender : mLifetimeExtenders) { - if (extender.shouldExtendLifetime(entry, reason)) { - entry.mLifetimeExtenders.add(extender); - } + if (isDismissedByUser(entry)) { + // User-dismissed notifications cannot be lifetime-extended + cancelLifetimeExtension(entry); + } else { + updateLifetimeExtension(entry); } - mAmDispatchingToOtherCode = false; if (!isLifetimeExtended(entry)) { mNotificationSet.remove(entry.getKey()); - - if (dismissedByUserStats != null) { - try { - mStatusBarService.onNotificationClear( - entry.getSbn().getPackageName(), - entry.getSbn().getTag(), - entry.getSbn().getId(), - entry.getSbn().getUser().getIdentifier(), - entry.getSbn().getKey(), - dismissedByUserStats.dismissalSurface, - dismissedByUserStats.dismissalSentiment, - dismissedByUserStats.notificationVisibility); - } catch (RemoteException e) { - // system process is dead if we're here. - } - } - - if (rankingMap != null) { - applyRanking(rankingMap); - } - - dispatchOnEntryRemoved(entry, reason, dismissedByUserStats != null /* removedByUser */); + dispatchOnEntryRemoved(entry, entry.mCancellationReason); + dispatchOnEntryCleanUp(entry); + return true; + } else { + return false; } - - rebuildList(); } private void applyRanking(@NonNull RankingMap rankingMap) { for (NotificationEntry entry : mNotificationSet.values()) { - if (!isLifetimeExtended(entry)) { - Ranking ranking = requireRanking(rankingMap, entry.getKey()); - entry.setRanking(ranking); - - // TODO: (b/145659174) update the sbn's overrideGroupKey in - // NotificationEntry.setRanking instead of here once we fully migrate to the - // NewNotifPipeline - if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { - final String newOverrideGroupKey = ranking.getOverrideGroupKey(); - if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), - newOverrideGroupKey)) { - entry.getSbn().setOverrideGroupKey(newOverrideGroupKey); + if (!isCanceled(entry)) { + + // TODO: (b/148791039) We should crash if we are ever handed a ranking with + // incomplete entries. Right now, there's a race condition in NotificationListener + // that means this might occur when SystemUI is starting up. + Ranking ranking = new Ranking(); + if (rankingMap.getRanking(entry.getKey(), ranking)) { + entry.setRanking(ranking); + + // TODO: (b/145659174) update the sbn's overrideGroupKey in + // NotificationEntry.setRanking instead of here once we fully migrate to the + // NewNotifPipeline + if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { + final String newOverrideGroupKey = ranking.getOverrideGroupKey(); + if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), + newOverrideGroupKey)) { + entry.getSbn().setOverrideGroupKey(newOverrideGroupKey); + } } + } else { + mLogger.logRankingMissing(entry.getKey(), rankingMap); } } } @@ -344,9 +406,9 @@ public class NotifCollection implements Dumpable { } if (!isLifetimeExtended(entry)) { - // TODO: This doesn't need to be undefined -- we can set either EXTENDER_EXPIRED or - // save the original reason - removeNotification(entry.getKey(), null, REASON_UNKNOWN, null); + if (tryRemoveNotification(entry)) { + rebuildList(); + } } } @@ -363,6 +425,31 @@ public class NotifCollection implements Dumpable { return entry.mLifetimeExtenders.size() > 0; } + private void updateLifetimeExtension(NotificationEntry entry) { + entry.mLifetimeExtenders.clear(); + mAmDispatchingToOtherCode = true; + for (NotifLifetimeExtender extender : mLifetimeExtenders) { + if (extender.shouldExtendLifetime(entry, entry.mCancellationReason)) { + entry.mLifetimeExtenders.add(extender); + } + } + mAmDispatchingToOtherCode = false; + } + + private void cancelLocalDismissal(NotificationEntry entry) { + if (isDismissedByUser(entry)) { + entry.setDismissState(NOT_DISMISSED); + if (entry.getSbn().getNotification().isGroupSummary()) { + for (NotificationEntry otherEntry : mNotificationSet.values()) { + if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey()) + && otherEntry.getDismissState() == PARENT_DISMISSED) { + otherEntry.setDismissState(NOT_DISMISSED); + } + } + } + } + } + private void checkForReentrantCall() { if (mAmDispatchingToOtherCode) { throw new IllegalStateException("Reentrant call detected"); @@ -378,6 +465,27 @@ public class NotifCollection implements Dumpable { return ranking; } + /** + * True if the notification has been canceled by system server. Usually, such notifications are + * immediately removed from the collection, but can sometimes stick around due to lifetime + * extenders. + */ + private static boolean isCanceled(NotificationEntry entry) { + return entry.mCancellationReason != REASON_NOT_CANCELED; + } + + private static boolean isDismissedByUser(NotificationEntry entry) { + return entry.getDismissState() != NOT_DISMISSED; + } + + private void dispatchOnEntryInit(NotificationEntry entry) { + mAmDispatchingToOtherCode = true; + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryInit(entry); + } + mAmDispatchingToOtherCode = false; + } + private void dispatchOnEntryAdded(NotificationEntry entry) { mAmDispatchingToOtherCode = true; for (NotifCollectionListener listener : mNotifCollectionListeners) { @@ -402,16 +510,35 @@ public class NotifCollection implements Dumpable { mAmDispatchingToOtherCode = false; } - private void dispatchOnEntryRemoved( - NotificationEntry entry, - @CancellationReason int reason, - boolean removedByUser) { + private void dispatchOnEntryRemoved(NotificationEntry entry, @CancellationReason int reason) { + mAmDispatchingToOtherCode = true; + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryRemoved(entry, reason); + } + mAmDispatchingToOtherCode = false; + } + + private void dispatchOnEntryCleanUp(NotificationEntry entry) { mAmDispatchingToOtherCode = true; for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryRemoved(entry, reason, removedByUser); + listener.onEntryCleanUp(entry); } mAmDispatchingToOtherCode = false; } + @Override + public void dump(@NonNull FileDescriptor fd, PrintWriter pw, @NonNull String[] args) { + final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs()); + + pw.println("\t" + TAG + " unsorted/unfiltered notifications:"); + if (entries.size() == 0) { + pw.println("\t\t None"); + } + pw.println( + ListDumper.dumpList( + entries, + true, + "\t\t")); + } private final BatchableNotificationHandler mNotifHandler = new BatchableNotificationHandler() { @Override @@ -467,20 +594,6 @@ public class NotifCollection implements Dumpable { @Retention(RetentionPolicy.SOURCE) public @interface CancellationReason {} + public static final int REASON_NOT_CANCELED = -1; public static final int REASON_UNKNOWN = 0; - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs()); - - pw.println("\t" + TAG + " unsorted/unfiltered notifications:"); - if (entries.size() == 0) { - pw.println("\t\t None"); - } - pw.println( - ListDumper.dumpList( - entries, - true, - "\t\t")); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index e7b772f1c7b2..7a6d4f1c7d7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -98,13 +98,12 @@ public class NotifInflaterImpl implements NotifInflater { @Override public void run() { int dismissalSurface = NotificationStats.DISMISSAL_SHADE; - /** + /* * TODO: determine dismissal surface (ie: shade / headsup / aod) * see {@link NotificationLogger#logNotificationClear} */ mNotifCollection.dismissNotification( entry, - 0, new DismissedByUserStats( dismissalSurface, DISMISS_SENTIMENT_NEUTRAL, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java index 0377f57a7a9c..9142388374e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java @@ -90,7 +90,8 @@ public class NotifPipeline { } /** - * Registers a listener to be informed when notifications are added, removed or updated. + * Registers a listener to be informed when there is a notification entry event such as an add, + * update, or remove. */ public void addCollectionListener(NotifCollectionListener listener) { mNotifCollection.addCollectionListener(listener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 1f77ec229041..a95668b5e48d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -29,9 +29,11 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; -import android.annotation.NonNull; +import static java.util.Objects.requireNonNull; + import android.app.Notification; import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; @@ -50,6 +52,7 @@ import android.util.ArraySet; import android.view.View; import android.widget.ImageView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; @@ -59,6 +62,7 @@ import com.android.internal.util.ContrastColorUtil; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.InflationException; +import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; @@ -105,9 +109,18 @@ public final class NotificationEntry extends ListEntry { /** If this was a group child that was promoted to the top level, then who did the promoting. */ @Nullable NotifPromoter mNotifPromoter; - /** If this notification had an issue with inflating. Only used with the NewNotifPipeline **/ + /** + * If this notification was cancelled by system server, then the reason that was supplied. + * Uncancelled notifications always have REASON_NOT_CANCELED. Note that lifetime-extended + * notifications will have this set even though they are still in the active notification set. + */ + @CancellationReason int mCancellationReason = REASON_NOT_CANCELED; + + /** @see #hasInflationError() */ private boolean mHasInflationError; + /** @see #getDismissState() */ + @NonNull private DismissState mDismissState = DismissState.NOT_DISMISSED; /* * Old members @@ -169,9 +182,9 @@ public final class NotificationEntry extends ListEntry { public NotificationEntry( @NonNull StatusBarNotification sbn, @NonNull Ranking ranking) { - super(Objects.requireNonNull(Objects.requireNonNull(sbn).getKey())); + super(requireNonNull(requireNonNull(sbn).getKey())); - Objects.requireNonNull(ranking); + requireNonNull(ranking); mKey = sbn.getKey(); setSbn(sbn); @@ -201,8 +214,8 @@ public final class NotificationEntry extends ListEntry { * TODO: Make this package-private */ public void setSbn(@NonNull StatusBarNotification sbn) { - Objects.requireNonNull(sbn); - Objects.requireNonNull(sbn.getKey()); + requireNonNull(sbn); + requireNonNull(sbn.getKey()); if (!sbn.getKey().equals(mKey)) { throw new IllegalArgumentException("New key " + sbn.getKey() @@ -227,8 +240,8 @@ public final class NotificationEntry extends ListEntry { * TODO: Make this package-private */ public void setRanking(@NonNull Ranking ranking) { - Objects.requireNonNull(ranking); - Objects.requireNonNull(ranking.getKey()); + requireNonNull(ranking); + requireNonNull(ranking.getKey()); if (!ranking.getKey().equals(mKey)) { throw new IllegalArgumentException("New key " + ranking.getKey() @@ -239,6 +252,34 @@ public final class NotificationEntry extends ListEntry { } /* + * Bookkeeping getters and setters + */ + + /** + * Whether this notification had an error when attempting to inflate. This is only used in + * the NewNotifPipeline + */ + public boolean hasInflationError() { + return mHasInflationError; + } + + void setHasInflationError(boolean hasError) { + mHasInflationError = hasError; + } + + /** + * Set if the user has dismissed this notif but we haven't yet heard back from system server to + * confirm the dismissal. + */ + @NonNull public DismissState getDismissState() { + return mDismissState; + } + + void setDismissState(@NonNull DismissState dismissState) { + mDismissState = requireNonNull(dismissState); + } + + /* * Convenience getters for SBN and Ranking members */ @@ -275,7 +316,6 @@ public final class NotificationEntry extends ListEntry { return mRanking.canBubble(); } - public @NonNull List<Notification.Action> getSmartActions() { return mRanking.getSmartActions(); } @@ -578,18 +618,6 @@ public final class NotificationEntry extends ListEntry { remoteInputTextWhenReset = null; } - void setHasInflationError(boolean hasError) { - mHasInflationError = hasError; - } - - /** - * Whether this notification had an error when attempting to inflate. This is only used in - * the NewNotifPipeline - */ - public boolean hasInflationError() { - return mHasInflationError; - } - public void setHasSentReply() { hasSentReply = true; } @@ -974,6 +1002,16 @@ public final class NotificationEntry extends ListEntry { } } + /** @see #getDismissState() */ + public enum DismissState { + /** User has not dismissed this notif or its parent */ + NOT_DISMISSED, + /** User has dismissed this notif specifically */ + DISMISSED, + /** User has dismissed this notif's parent (which implicitly dismisses this one as well) */ + PARENT_DISMISSED, + } + private static final long LAUNCH_COOLDOWN = 2000; private static final long REMOTE_INPUT_COOLDOWN = 500; private static final long INITIALIZATION_DELAY = 400; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java new file mode 100644 index 000000000000..0059e7baa3c2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java @@ -0,0 +1,41 @@ +/* + * 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.notification.collection.coordinator; + +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; + +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; + +/** + * Filters out notifications that have been dismissed locally (by the user) but that system server + * hasn't yet confirmed the removal of. + */ +public class HideLocallyDismissedNotifsCoordinator implements Coordinator { + @Override + public void attach(NotifPipeline pipeline) { + pipeline.addPreGroupFilter(mFilter); + } + + private final NotifFilter mFilter = new NotifFilter("HideLocallyDismissedNotifsFilter") { + @Override + public boolean shouldFilterOut(NotificationEntry entry, long now) { + return entry.getDismissState() != NOT_DISMISSED; + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java index 8d0dd5b111ba..0a1e09f4c99d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java @@ -56,6 +56,7 @@ public class NotifCoordinators implements Dumpable { PreparationCoordinator preparationCoordinator) { dumpController.registerDumpable(TAG, this); + mCoordinators.add(new HideLocallyDismissedNotifsCoordinator()); mCoordinators.add(keyguardCoordinator); mCoordinators.add(rankingCoordinator); mCoordinators.add(foregroundCoordinator); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 20c9cbc8790d..41314b86695a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -72,7 +72,7 @@ public class PreparationCoordinator implements Coordinator { } @Override - public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) { + public void onEntryRemoved(NotificationEntry entry, int reason) { abortInflation(entry, "entryRemoved reason=" + reason); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java index 6adcabd86fe6..b2c53dae16cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java @@ -18,15 +18,25 @@ package com.android.systemui.statusbar.notification.collection.notifcollection; import android.service.notification.NotificationListenerService; -import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** - * Listener interface for {@link NotifCollection}. + * Listener interface for {@link NotificationEntry} events. */ public interface NotifCollectionListener { /** + * Called whenever a new {@link NotificationEntry} is initialized. This should be used for + * initializing any decorated state tied to the notification. + * + * Do not reference other registered {@link NotifCollectionListener} implementations here as + * there is no guarantee of order and they may not have had a chance to initialize yet. Instead, + * use {@link #onEntryAdded} which is called after all initialization. + */ + default void onEntryInit(NotificationEntry entry) { + } + + /** * Called whenever a notification with a new key is posted. */ default void onEntryAdded(NotificationEntry entry) { @@ -44,10 +54,19 @@ public interface NotifCollectionListener { * immediately after a user dismisses a notification: we wait until we receive confirmation from * system server before considering the notification removed. */ - default void onEntryRemoved( - NotificationEntry entry, - @CancellationReason int reason, - boolean removedByUser) { + default void onEntryRemoved(NotificationEntry entry, @CancellationReason int reason) { + } + + /** + * Called whenever a {@link NotificationEntry} is considered deleted. This should be used for + * cleaning up any state tied to the notification. + * + * This is the deletion parallel of {@link #onEntryInit} and similarly means that you cannot + * expect other {@link NotifCollectionListener} implementations to still have valid state for + * the entry during this call. Instead, use {@link #onEntryRemoved} which will be called before + * deletion. + */ + default void onEntryCleanUp(NotificationEntry entry) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt index bd1bd860f80c..14e15031056f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt @@ -16,8 +16,11 @@ package com.android.systemui.statusbar.notification.collection.notifcollection +import android.service.notification.NotificationListenerService.RankingMap import com.android.systemui.log.LogBuffer -import com.android.systemui.log.LogLevel +import com.android.systemui.log.LogLevel.DEBUG +import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationLog import javax.inject.Inject @@ -25,7 +28,7 @@ class NotifCollectionLogger @Inject constructor( @NotificationLog private val buffer: LogBuffer ) { fun logNotifPosted(key: String) { - buffer.log(TAG, LogLevel.INFO, { + buffer.log(TAG, INFO, { str1 = key }, { "POSTED $str1" @@ -33,7 +36,7 @@ class NotifCollectionLogger @Inject constructor( } fun logNotifGroupPosted(groupKey: String, batchSize: Int) { - buffer.log(TAG, LogLevel.INFO, { + buffer.log(TAG, INFO, { str1 = groupKey int1 = batchSize }, { @@ -42,7 +45,7 @@ class NotifCollectionLogger @Inject constructor( } fun logNotifUpdated(key: String) { - buffer.log(TAG, LogLevel.INFO, { + buffer.log(TAG, INFO, { str1 = key }, { "UPDATED $str1" @@ -50,13 +53,29 @@ class NotifCollectionLogger @Inject constructor( } fun logNotifRemoved(key: String, reason: Int) { - buffer.log(TAG, LogLevel.INFO, { + buffer.log(TAG, INFO, { str1 = key int1 = reason }, { "REMOVED $str1 reason=$int1" }) } + + fun logNotifDismissed(key: String) { + buffer.log(TAG, INFO, { + str1 = key + }, { + "DISMISSED $str1" + }) + } + + fun logRankingMissing(key: String, rankingMap: RankingMap) { + buffer.log(TAG, WARNING, { str1 = key }, { "Ranking update is missing ranking for $str1" }) + buffer.log(TAG, DEBUG, {}, { "Ranking map contents:" }) + for (entry in rankingMap.orderedKeys) { + buffer.log(TAG, DEBUG, { str1 = entry }, { " $str1" }) + } + } } private const val TAG = "NotifCollection"
\ No newline at end of file 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 new file mode 100644 index 000000000000..c7666e47d4b4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -0,0 +1,48 @@ +/* + * 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.notification.dagger; + +import android.content.Context; + +import com.android.systemui.R; +import com.android.systemui.statusbar.notification.init.NotificationsController; +import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; +import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; + +import javax.inject.Singleton; + +import dagger.Lazy; +import dagger.Module; +import dagger.Provides; + +/** Module for classes related to the notifications data pipeline */ +@Module +public class NotificationsModule { + /** Initializes the notification data pipeline (can be disabled via config). */ + @Singleton + @Provides + static NotificationsController provideNotificationsController( + Context context, + Lazy<NotificationsControllerImpl> realController, + Lazy<NotificationsControllerStub> stubController) { + if (context.getResources().getBoolean(R.bool.config_renderNotifications)) { + return realController.get(); + } else { + return stubController.get(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt new file mode 100644 index 000000000000..9da8b8a3fd92 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt @@ -0,0 +1,50 @@ +/* + * 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.notification.init + +import android.service.notification.StatusBarNotification +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption +import com.android.systemui.statusbar.NotificationPresenter +import com.android.systemui.statusbar.notification.NotificationActivityStarter +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl +import com.android.systemui.statusbar.notification.stack.NotificationListContainer +import com.android.systemui.statusbar.phone.StatusBar +import java.io.FileDescriptor +import java.io.PrintWriter + +/** + * The master controller for all notifications-related work + * + * Split into two implementations: [NotificationsControllerImpl] (most cases) and + * [NotificationsControllerStub] (for builds that disable notification rendering). + */ +interface NotificationsController { + fun initialize( + statusBar: StatusBar, + presenter: NotificationPresenter, + listContainer: NotificationListContainer, + notificationActivityStarter: NotificationActivityStarter, + bindRowCallback: NotificationRowBinderImpl.BindRowCallback + ) + + fun requestNotificationUpdate(reason: String) + fun resetUserExpandedStates() + fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) + fun getActiveNotificationsCount(): Int + fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int) + fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>, dumpTruck: Boolean) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt new file mode 100644 index 000000000000..61e3192eba3c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -0,0 +1,157 @@ +/* + * 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.notification.init + +import android.service.notification.StatusBarNotification +import com.android.systemui.bubbles.BubbleController +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption +import com.android.systemui.statusbar.FeatureFlags +import com.android.systemui.statusbar.NotificationListener +import com.android.systemui.statusbar.NotificationPresenter +import com.android.systemui.statusbar.notification.NotificationActivityStarter +import com.android.systemui.statusbar.notification.NotificationClicker +import com.android.systemui.statusbar.notification.NotificationEntryManager +import com.android.systemui.statusbar.notification.NotificationListController +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer +import com.android.systemui.statusbar.notification.stack.NotificationListContainer +import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper +import com.android.systemui.statusbar.phone.NotificationGroupManager +import com.android.systemui.statusbar.phone.StatusBar +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.HeadsUpManager +import com.android.systemui.statusbar.policy.RemoteInputUriController +import dagger.Lazy +import java.io.FileDescriptor +import java.io.PrintWriter +import java.util.Optional +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Master controller for all notifications-related work + * + * At the moment exposes a number of event-handler-esque methods; these are for historical reasons. + * Once we migrate away from the need for such things, this class becomes primarily a place to do + * any initialization work that notifications require. + */ +@Singleton +class NotificationsControllerImpl @Inject constructor( + private val featureFlags: FeatureFlags, + private val notificationListener: NotificationListener, + private val entryManager: NotificationEntryManager, + private val newNotifPipeline: Lazy<NotifPipelineInitializer>, + private val deviceProvisionedController: DeviceProvisionedController, + private val notificationRowBinder: NotificationRowBinderImpl, + private val remoteInputUriController: RemoteInputUriController, + private val bubbleController: BubbleController, + private val groupManager: NotificationGroupManager, + private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper, + private val headsUpManager: HeadsUpManager +) : NotificationsController { + + override fun initialize( + statusBar: StatusBar, + presenter: NotificationPresenter, + listContainer: NotificationListContainer, + notificationActivityStarter: NotificationActivityStarter, + bindRowCallback: NotificationRowBinderImpl.BindRowCallback + ) { + notificationListener.registerAsSystemService() + + val listController = + NotificationListController( + entryManager, + listContainer, + deviceProvisionedController) + listController.bind() + + notificationRowBinder.setNotificationClicker( + NotificationClicker( + Optional.of(statusBar), + bubbleController, + notificationActivityStarter)) + notificationRowBinder.setUpWithPresenter( + presenter, + listContainer, + headsUpManager, + bindRowCallback) + + if (featureFlags.isNewNotifPipelineEnabled) { + newNotifPipeline.get().initialize(notificationListener, notificationRowBinder) + } + + if (featureFlags.isNewNotifPipelineRenderingEnabled) { + // TODO + } else { + notificationRowBinder.setInflationCallback(entryManager) + + remoteInputUriController.attach(entryManager) + groupAlertTransferHelper.bind(entryManager, groupManager) + headsUpManager.addListener(groupManager) + headsUpManager.addListener(groupAlertTransferHelper) + groupManager.setHeadsUpManager(headsUpManager) + groupAlertTransferHelper.setHeadsUpManager(headsUpManager) + + entryManager.attach(notificationListener) + } + } + + override fun dump( + fd: FileDescriptor, + pw: PrintWriter, + args: Array<String>, + dumpTruck: Boolean + ) { + if (dumpTruck) { + entryManager.dump(pw, " ") + } + groupManager.dump(fd, pw, args) + } + + // TODO: Convert all functions below this line into listeners instead of public methods + + override fun requestNotificationUpdate(reason: String) { + entryManager.updateNotifications(reason) + } + + override fun resetUserExpandedStates() { + for (entry in entryManager.visibleNotifications) { + entry.resetUserExpansion() + } + } + + override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) { + if (snoozeOption.snoozeCriterion != null) { + notificationListener.snoozeNotification(sbn.key, snoozeOption.snoozeCriterion.id) + } else { + notificationListener.snoozeNotification( + sbn.key, + snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong()) + } + } + + override fun getActiveNotificationsCount(): Int { + return entryManager.activeNotificationsCount + } + + override fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int) { + notificationListener.snoozeNotification( + sbn.key, + hoursToSnooze * 60 * 60 * 1000.toLong()) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt new file mode 100644 index 000000000000..ded855dd84f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt @@ -0,0 +1,76 @@ +/* + * 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.notification.init + +import android.service.notification.StatusBarNotification +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption +import com.android.systemui.statusbar.NotificationListener +import com.android.systemui.statusbar.NotificationPresenter +import com.android.systemui.statusbar.notification.NotificationActivityStarter +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl +import com.android.systemui.statusbar.notification.stack.NotificationListContainer +import com.android.systemui.statusbar.phone.StatusBar +import java.io.FileDescriptor +import java.io.PrintWriter +import javax.inject.Inject + +/** + * Implementation of [NotificationsController] that's used when notifications rendering is disabled. + */ +class NotificationsControllerStub @Inject constructor( + private val notificationListener: NotificationListener +) : NotificationsController { + + override fun initialize( + statusBar: StatusBar, + presenter: NotificationPresenter, + listContainer: NotificationListContainer, + notificationActivityStarter: NotificationActivityStarter, + bindRowCallback: NotificationRowBinderImpl.BindRowCallback + ) { + // Always connect the listener even if notification-handling is disabled. Being a listener + // grants special permissions and it's not clear if other things will break if we lose those + notificationListener.registerAsSystemService() + } + + override fun requestNotificationUpdate(reason: String) { + } + + override fun resetUserExpandedStates() { + } + + override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) { + } + + override fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int) { + } + + override fun getActiveNotificationsCount(): Int { + return 0 + } + + override fun dump( + fd: FileDescriptor, + pw: PrintWriter, + args: Array<String>, + dumpTruck: Boolean + ) { + pw.println() + pw.println("Notification handling disabled") + pw.println() + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index 28f4136d5ecb..049cafa4ccde 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -93,7 +93,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { } else { Path clipPath = getClipPath(false /* ignoreTranslation */); if (clipPath != null) { - outline.setConvexPath(clipPath); + outline.setPath(clipPath); } } outline.setAlpha(mOutlineAlpha); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 1726b4884aff..11f70796748c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -168,12 +168,10 @@ import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.EmptyShadeView; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyboardShortcuts; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; @@ -191,15 +189,11 @@ import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationClicker; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; -import com.android.systemui.statusbar.notification.NotificationListController; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -218,7 +212,6 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.volume.VolumeComponent; @@ -356,7 +349,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final Object mQueueLock = new Object(); - private final FeatureFlags mFeatureFlags; private final StatusBarIconController mIconController; private final PulseExpansionHandler mPulseExpansionHandler; private final NotificationWakeUpCoordinator mWakeUpCoordinator; @@ -365,7 +357,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final HeadsUpManagerPhone mHeadsUpManager; private final DynamicPrivacyController mDynamicPrivacyController; private final BypassHeadsUpNotifier mBypassHeadsUpNotifier; - private final Lazy<NotifPipelineInitializer> mNewNotifPipeline; private final FalsingManager mFalsingManager; private final BroadcastDispatcher mBroadcastDispatcher; private final ConfigurationController mConfigurationController; @@ -374,7 +365,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder; private final PluginManager mPluginManager; - private final RemoteInputUriController mRemoteInputUriController; private final Optional<Divider> mDividerOptional; private final StatusBarNotificationActivityStarter.Builder mStatusBarNotificationActivityStarterBuilder; @@ -387,8 +377,8 @@ public class StatusBar extends SystemUI implements DemoMode, private final KeyguardDismissUtil mKeyguardDismissUtil; private final ExtensionController mExtensionController; private final UserInfoControllerImpl mUserInfoControllerImpl; - private final NotificationRowBinderImpl mNotificationRowBinder; private final DismissCallbackRegistry mDismissCallbackRegistry; + private NotificationsController mNotificationsController; // expanded notifications // the sliding/resizing panel within the notification window @@ -412,8 +402,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final NotificationGutsManager mGutsManager; private final NotificationLogger mNotificationLogger; - private final NotificationEntryManager mEntryManager; - private NotificationListController mNotificationListController; private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private final NotificationViewHierarchyManager mViewHierarchyManager; private final KeyguardViewMediator mKeyguardViewMediator; @@ -589,7 +577,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onStrongAuthStateChanged(int userId) { super.onStrongAuthStateChanged(userId); - mEntryManager.updateNotifications("onStrongAuthStateChanged"); + mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged"); } }; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); @@ -614,7 +602,7 @@ public class StatusBar extends SystemUI implements DemoMode, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public StatusBar( Context context, - FeatureFlags featureFlags, + NotificationsController notificationsController, LightBarController lightBarController, AutoHideController autoHideController, KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -626,13 +614,11 @@ public class StatusBar extends SystemUI implements DemoMode, HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NotifPipelineInitializer> newNotifPipeline, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, NotificationInterruptionStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, @@ -653,12 +639,10 @@ public class StatusBar extends SystemUI implements DemoMode, VibratorHelper vibratorHelper, BubbleController bubbleController, NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, Lazy<AssistManager> assistManagerLazy, - NotificationListener notificationListener, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, LockscreenLockIconController lockscreenLockIconController, @@ -676,7 +660,6 @@ public class StatusBar extends SystemUI implements DemoMode, Optional<Recents> recentsOptional, Provider<StatusBarComponent.Builder> statusBarComponentBuilder, PluginManager pluginManager, - RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, LightsOutNotifController lightsOutNotifController, StatusBarNotificationActivityStarter.Builder @@ -692,10 +675,9 @@ public class StatusBar extends SystemUI implements DemoMode, KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, - NotificationRowBinderImpl notificationRowBinder, DismissCallbackRegistry dismissCallbackRegistry) { super(context); - mFeatureFlags = featureFlags; + mNotificationsController = notificationsController; mLightBarController = lightBarController; mAutoHideController = autoHideController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -707,13 +689,11 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager = headsUpManagerPhone; mDynamicPrivacyController = dynamicPrivacyController; mBypassHeadsUpNotifier = bypassHeadsUpNotifier; - mNewNotifPipeline = newNotifPipeline; mFalsingManager = falsingManager; mBroadcastDispatcher = broadcastDispatcher; mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; mGutsManager = notificationGutsManager; mNotificationLogger = notificationLogger; - mEntryManager = notificationEntryManager; mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; mViewHierarchyManager = notificationViewHierarchyManager; mKeyguardViewMediator = keyguardViewMediator; @@ -734,12 +714,10 @@ public class StatusBar extends SystemUI implements DemoMode, mVibratorHelper = vibratorHelper; mBubbleController = bubbleController; mGroupManager = groupManager; - mGroupAlertTransferHelper = groupAlertTransferHelper; mVisualStabilityManager = visualStabilityManager; mDeviceProvisionedController = deviceProvisionedController; mNavigationBarController = navigationBarController; mAssistManagerLazy = assistManagerLazy; - mNotificationListener = notificationListener; mConfigurationController = configurationController; mNotificationShadeWindowController = notificationShadeWindowController; mLockscreenLockIconController = lockscreenLockIconController; @@ -757,7 +735,6 @@ public class StatusBar extends SystemUI implements DemoMode, mRecentsOptional = recentsOptional; mStatusBarComponentBuilder = statusBarComponentBuilder; mPluginManager = pluginManager; - mRemoteInputUriController = remoteInputUriController; mDividerOptional = dividerOptional; mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder; mShadeController = shadeController; @@ -771,12 +748,11 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardDismissUtil = keyguardDismissUtil; mExtensionController = extensionController; mUserInfoControllerImpl = userInfoControllerImpl; - mNotificationRowBinder = notificationRowBinder; mDismissCallbackRegistry = dismissCallbackRegistry; mBubbleExpandListener = (isExpanding, key) -> { - mEntryManager.updateNotifications("onBubbleExpandChanged"); + mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged"); updateScrimController(); }; @@ -786,11 +762,10 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void start() { - mNotificationListener.registerAsSystemService(); mScreenLifecycle.addObserver(mScreenObserver); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); mUiModeManager = mContext.getSystemService(UiModeManager.class); - mBypassHeadsUpNotifier.setUp(mEntryManager); + mBypassHeadsUpNotifier.setUp(); mBubbleController.setExpandListener(mBubbleExpandListener); mActivityIntentHelper = new ActivityIntentHelper(mContext); @@ -1060,12 +1035,8 @@ public class StatusBar extends SystemUI implements DemoMode, mConfigurationController.addCallback(mHeadsUpManager); mHeadsUpManager.addListener(this); mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener()); - mHeadsUpManager.addListener(mGroupManager); - mHeadsUpManager.addListener(mGroupAlertTransferHelper); mHeadsUpManager.addListener(mVisualStabilityManager); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); - mGroupManager.setHeadsUpManager(mHeadsUpManager); - mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager); mNotificationLogger.setHeadsUpManager(mHeadsUpManager); createNavigationBar(result); @@ -1243,16 +1214,10 @@ public class StatusBar extends SystemUI implements DemoMode, mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController, mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, - mNotificationAlertingManager, mNotificationRowBinder, mKeyguardStateController, + mNotificationAlertingManager, mKeyguardStateController, mKeyguardIndicationController, this /* statusBar */, mShadeController, mCommandQueue, mInitController); - mNotificationListController = - new NotificationListController( - mEntryManager, - (NotificationListContainer) mStackScroller, - mDeviceProvisionedController); - mNotificationShelf.setOnActivatedListener(mPresenter); mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController); @@ -1266,22 +1231,12 @@ public class StatusBar extends SystemUI implements DemoMode, mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); - if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { - mNotificationRowBinder.setInflationCallback(mEntryManager); - } - - mRemoteInputUriController.attach(mEntryManager); - - mNotificationRowBinder.setNotificationClicker(new NotificationClicker( - Optional.of(this), mBubbleController, mNotificationActivityStarter)); - - mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager); - mNotificationListController.bind(); - - if (mFeatureFlags.isNewNotifPipelineEnabled()) { - mNewNotifPipeline.get().initialize(mNotificationListener, mNotificationRowBinder); - } - mEntryManager.attach(mNotificationListener); + mNotificationsController.initialize( + this, + mPresenter, + (NotificationListContainer) mStackScroller, + mNotificationActivityStarter, + mPresenter); } /** @@ -1518,7 +1473,7 @@ public class StatusBar extends SystemUI implements DemoMode, * @param reason why we're requesting a notification update */ public void requestNotificationUpdate(String reason) { - mEntryManager.updateNotifications(reason); + mNotificationsController.requestNotificationUpdate(reason); } /** @@ -1726,7 +1681,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { - mEntryManager.updateNotifications("onHeadsUpStateChanged"); + mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged"); if (mStatusBarStateController.isDozing() && isHeadsUp) { entry.setPulseSuppressed(false); mDozeServiceHost.fireNotificationPulse(entry); @@ -2485,11 +2440,9 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarKeyguardViewManager.dump(pw); } - if (DUMPTRUCK) { - synchronized (mEntryManager) { - mEntryManager.dump(pw, " "); - } + mNotificationsController.dump(fd, pw, args, DUMPTRUCK); + if (DUMPTRUCK) { if (false) { pw.println("see the logcat for a dump of the views we have created."); // must happen on ui thread @@ -2512,11 +2465,6 @@ public class StatusBar extends SystemUI implements DemoMode, } else { pw.println(" mHeadsUpManager: null"); } - if (mGroupManager != null) { - mGroupManager.dump(fd, pw, args); - } else { - pw.println(" mGroupManager: null"); - } if (mBubbleController != null) { mBubbleController.dump(fd, pw, args); @@ -2747,9 +2695,7 @@ public class StatusBar extends SystemUI implements DemoMode, }; public void resetUserExpandedStates() { - for (NotificationEntry entry : mEntryManager.getVisibleNotifications()) { - entry.resetUserExpansion(); - } + mNotificationsController.resetUserExpandedStates(); } private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) { @@ -2855,7 +2801,7 @@ public class StatusBar extends SystemUI implements DemoMode, try { // consider the transition from peek to expanded to be a panel open, // but not one that clears notification effects. - int notificationLoad = mEntryManager.getActiveNotificationsCount(); + int notificationLoad = mNotificationsController.getActiveNotificationsCount(); mBarService.onPanelRevealed(false, notificationLoad); } catch (RemoteException ex) { // Won't fail unless the world has ended. @@ -2873,7 +2819,7 @@ public class StatusBar extends SystemUI implements DemoMode, !mPresenter.isPresenterFullyCollapsed() && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED); - int notificationLoad = mEntryManager.getActiveNotificationsCount(); + int notificationLoad = mNotificationsController.getActiveNotificationsCount(); if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) { notificationLoad = 1; } @@ -3514,7 +3460,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateQsExpansionEnabled(); mKeyguardViewMediator.setDozing(mDozing); - mEntryManager.updateNotifications("onDozingChanged"); + mNotificationsController.requestNotificationUpdate("onDozingChanged"); updateDozingState(); mDozeServiceHost.updateDozing(); updateScrimController(); @@ -3965,7 +3911,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected ViewGroup mStackScroller; private final NotificationGroupManager mGroupManager; - private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; // handling reordering private final VisualStabilityManager mVisualStabilityManager; @@ -4032,21 +3977,12 @@ public class StatusBar extends SystemUI implements DemoMode, } }; - private final NotificationListener mNotificationListener; - public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) { - if (snoozeOption.getSnoozeCriterion() != null) { - mNotificationListener.snoozeNotification(sbn.getKey(), - snoozeOption.getSnoozeCriterion().getId()); - } else { - mNotificationListener.snoozeNotification(sbn.getKey(), - snoozeOption.getMinutesToSnoozeFor() * 60 * 1000); - } + mNotificationsController.setNotificationSnoozed(sbn, snoozeOption); } public void setNotificationSnoozed(StatusBarNotification sbn, int hoursToSnooze) { - mNotificationListener.snoozeNotification(sbn.getKey(), - hoursToSnooze * 60 * 60 * 1000); + mNotificationsController.setNotificationSnoozed(sbn, hoursToSnooze); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java index 7615bf826287..15a0e08e285f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java @@ -46,9 +46,7 @@ import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -61,12 +59,10 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -77,7 +73,6 @@ import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.volume.VolumeComponent; @@ -105,7 +100,7 @@ public class StatusBarModule { @Singleton static StatusBar provideStatusBar( Context context, - FeatureFlags featureFlags, + NotificationsController notificationsController, LightBarController lightBarController, AutoHideController autoHideController, KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -117,13 +112,11 @@ public class StatusBarModule { HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NotifPipelineInitializer> newNotifPipeline, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, NotificationInterruptionStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, @@ -144,12 +137,10 @@ public class StatusBarModule { VibratorHelper vibratorHelper, BubbleController bubbleController, NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, Lazy<AssistManager> assistManagerLazy, - NotificationListener notificationListener, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, LockscreenLockIconController lockscreenLockIconController, @@ -167,7 +158,6 @@ public class StatusBarModule { Optional<Recents> recentsOptional, Provider<StatusBarComponent.Builder> statusBarComponentBuilder, PluginManager pluginManager, - RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, LightsOutNotifController lightsOutNotifController, StatusBarNotificationActivityStarter.Builder @@ -183,11 +173,10 @@ public class StatusBarModule { KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, - NotificationRowBinderImpl notificationRowBinder, DismissCallbackRegistry dismissCallbackRegistry) { return new StatusBar( context, - featureFlags, + notificationsController, lightBarController, autoHideController, keyguardUpdateMonitor, @@ -199,13 +188,11 @@ public class StatusBarModule { headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, - newNotifPipeline, falsingManager, broadcastDispatcher, remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationEntryManager, notificationInterruptionStateProvider, notificationViewHierarchyManager, keyguardViewMediator, @@ -226,12 +213,10 @@ public class StatusBarModule { vibratorHelper, bubbleController, groupManager, - groupAlertTransferHelper, visualStabilityManager, deviceProvisionedController, navigationBarController, assistManagerLazy, - notificationListener, configurationController, notificationShadeWindowController, lockscreenLockIconController, @@ -249,7 +234,6 @@ public class StatusBarModule { recentsOptional, statusBarComponentBuilder, pluginManager, - remoteInputUriController, dividerOptional, lightsOutNotifController, statusBarNotificationActivityStarterBuilder, @@ -264,7 +248,6 @@ public class StatusBarModule { keyguardDismissUtil, extensionController, userInfoControllerImpl, - notificationRowBinder, dismissCallbackRegistry); } } 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 1336b2de82d3..2485513abba5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -141,7 +141,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, ActivityLaunchAnimator activityLaunchAnimator, DynamicPrivacyController dynamicPrivacyController, NotificationAlertingManager notificationAlertingManager, - NotificationRowBinderImpl notificationRowBinder, KeyguardStateController keyguardStateController, KeyguardIndicationController keyguardIndicationController, StatusBar statusBar, @@ -216,8 +215,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mEntryManager.addNotificationLifetimeExtender(mGutsManager); mEntryManager.addNotificationLifetimeExtenders( remoteInputManager.getLifetimeExtenders()); - notificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager, - this); mNotificationInterruptionStateProvider.setUpWithPresenter( this, mHeadsUpManager, this::canHeadsUp); mLockscreenUserManager.setUpWithPresenter(this); diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto index 08ae99ceb7a1..d940a6b5c460 100644 --- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto +++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto @@ -29,3 +29,29 @@ message EdgeBackGestureHandlerProto { optional bool allow_gesture = 1; } + +/* represents a file full of system ui trace entries. + Encoded, it should start with 0x9 0x53 0x59 0x53 0x55 0x49 0x54 0x52 0x43 (.SYSUITRC), such + that they can be easily identified. */ +message SystemUiTraceFileProto { + + /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L + (this is needed because enums have to be 32 bits and there's no nice way to put 64bit + constants into .proto files. */ + enum MagicNumber { + INVALID = 0; + MAGIC_NUMBER_L = 0x55535953; /* SYSU (little-endian ASCII) */ + MAGIC_NUMBER_H = 0x43525449; /* ITRC (little-endian ASCII) */ + } + + optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ + repeated SystemUiTraceEntryProto entry = 2; +} + +/* one system ui trace entry. */ +message SystemUiTraceEntryProto { + /* required: elapsed realtime in nanos since boot of when this entry was logged */ + optional fixed64 elapsed_realtime_nanos = 1; + + optional SystemUiTraceProto system_ui = 3; +} diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto deleted file mode 100644 index d1523ef13501..000000000000 --- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto2"; - -import "frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto"; - -package com.android.systemui.tracing; - -option java_multiple_files = true; - -/* represents a file full of system ui trace entries. - Encoded, it should start with 0x9 0x53 0x59 0x53 0x55 0x49 0x54 0x52 0x43 (.SYSUITRC), such - that they can be easily identified. */ -message SystemUiTraceFileProto { - - /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L - (this is needed because enums have to be 32 bits and there's no nice way to put 64bit - constants into .proto files. */ - enum MagicNumber { - INVALID = 0; - MAGIC_NUMBER_L = 0x55535953; /* SYSU (little-endian ASCII) */ - MAGIC_NUMBER_H = 0x43525449; /* ITRC (little-endian ASCII) */ - } - - optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ - repeated SystemUiTraceEntryProto entry = 2; -} - -/* one system ui trace entry. */ -message SystemUiTraceEntryProto { - /* required: elapsed realtime in nanos since boot of when this entry was logged */ - optional fixed64 elapsed_realtime_nanos = 1; - - optional SystemUiTraceProto system_ui = 3; -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt index 7c8c7c8f7be6..89c1636e953f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.controls.controller import android.content.ComponentName import android.content.Context import android.os.Binder +import android.os.UserHandle import android.service.controls.Control import android.service.controls.DeviceTypes import android.testing.AndroidTestingRunner @@ -38,6 +39,7 @@ import org.mockito.Mockito import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.Mockito.never +import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -55,6 +57,9 @@ class ControlsBindingControllerTest : SysuiTestCase() { @Mock private lateinit var mockControlsController: ControlsController + private val user = UserHandle.of(mContext.userId) + private val otherUser = UserHandle.of(user.identifier + 1) + private val executor = FakeExecutor(FakeSystemClock()) private lateinit var controller: ControlsBindingController private val providers = TestableControlsBindingControllerImpl.providers @@ -75,6 +80,11 @@ class ControlsBindingControllerTest : SysuiTestCase() { } @Test + fun testStartOnUser() { + assertEquals(user.identifier, controller.currentUserId) + } + + @Test fun testBindAndLoad() { val callback: (List<Control>) -> Unit = {} controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback) @@ -93,7 +103,7 @@ class ControlsBindingControllerTest : SysuiTestCase() { assertEquals(setOf(TEST_COMPONENT_NAME_1, TEST_COMPONENT_NAME_2), providers.map { it.componentName }.toSet()) providers.forEach { - verify(it).bindPermanently() + verify(it).bindService() } } @@ -145,6 +155,41 @@ class ControlsBindingControllerTest : SysuiTestCase() { verify(it).unsubscribe() } } + + @Test + fun testCurrentUserId() { + controller.changeUser(otherUser) + assertEquals(otherUser.identifier, controller.currentUserId) + } + + @Test + fun testChangeUsers_providersHaveCorrectUser() { + controller.bindServices(listOf(TEST_COMPONENT_NAME_1)) + controller.changeUser(otherUser) + controller.bindServices(listOf(TEST_COMPONENT_NAME_2)) + + val provider1 = providers.first { it.componentName == TEST_COMPONENT_NAME_1 } + assertEquals(user, provider1.user) + val provider2 = providers.first { it.componentName == TEST_COMPONENT_NAME_2 } + assertEquals(otherUser, provider2.user) + } + + @Test + fun testChangeUsers_providersUnbound() { + controller.bindServices(listOf(TEST_COMPONENT_NAME_1)) + controller.changeUser(otherUser) + + val provider1 = providers.first { it.componentName == TEST_COMPONENT_NAME_1 } + verify(provider1).unbindService() + + controller.bindServices(listOf(TEST_COMPONENT_NAME_2)) + controller.changeUser(user) + + reset(provider1) + val provider2 = providers.first { it.componentName == TEST_COMPONENT_NAME_2 } + verify(provider2).unbindService() + verify(provider1, never()).unbindService() + } } class TestableControlsBindingControllerImpl( @@ -157,13 +202,17 @@ class TestableControlsBindingControllerImpl( val providers = mutableSetOf<ControlsProviderLifecycleManager>() } + // Replaces the real provider with a mock and puts the mock in a visible set. + // The mock has the same componentName and user as the real one would have override fun createProviderManager(component: ComponentName): ControlsProviderLifecycleManager { + val realProvider = super.createProviderManager(component) val provider = mock(ControlsProviderLifecycleManager::class.java) val token = Binder() - `when`(provider.componentName).thenReturn(component) + `when`(provider.componentName).thenReturn(realProvider.componentName) `when`(provider.token).thenReturn(token) + `when`(provider.user).thenReturn(realProvider.user) providers.add(provider) return provider } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index be86a9c15e5f..897091f69f36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -17,7 +17,12 @@ package com.android.systemui.controls.controller import android.app.PendingIntent +import android.content.BroadcastReceiver import android.content.ComponentName +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.os.UserHandle import android.provider.Settings import android.service.controls.Control import android.service.controls.DeviceTypes @@ -26,6 +31,8 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.DumpController import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.util.concurrency.FakeExecutor @@ -37,10 +44,11 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers -import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify @@ -61,18 +69,25 @@ class ControlsControllerImplTest : SysuiTestCase() { private lateinit var pendingIntent: PendingIntent @Mock private lateinit var persistenceWrapper: ControlsFavoritePersistenceWrapper + @Mock + private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock + private lateinit var listingController: ControlsListingController @Captor private lateinit var controlInfoListCaptor: ArgumentCaptor<List<ControlInfo>> @Captor private lateinit var controlLoadCallbackCaptor: ArgumentCaptor<(List<Control>) -> Unit> + @Captor + private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver> private lateinit var delayableExecutor: FakeExecutor private lateinit var controller: ControlsController companion object { fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() - fun <T : Any> safeEq(value: T): T = eq(value) ?: value + fun <T> eq(value: T): T = Mockito.eq(value) ?: value + fun <T> any(): T = Mockito.any<T>() private val TEST_COMPONENT = ComponentName("test.pkg", "test.class") private const val TEST_CONTROL_ID = "control1" @@ -89,24 +104,39 @@ class ControlsControllerImplTest : SysuiTestCase() { TEST_COMPONENT_2, TEST_CONTROL_ID_2, TEST_CONTROL_TITLE_2, TEST_DEVICE_TYPE_2) } + private val user = mContext.userId + private val otherUser = user + 1 + @Before fun setUp() { MockitoAnnotations.initMocks(this) Settings.Secure.putInt(mContext.contentResolver, ControlsControllerImpl.CONTROLS_AVAILABLE, 1) + Settings.Secure.putIntForUser(mContext.contentResolver, + ControlsControllerImpl.CONTROLS_AVAILABLE, 1, otherUser) delayableExecutor = FakeExecutor(FakeSystemClock()) + val wrapper = object : ContextWrapper(mContext) { + override fun createContextAsUser(user: UserHandle, flags: Int): Context { + return baseContext + } + } + controller = ControlsControllerImpl( - mContext, + wrapper, delayableExecutor, uiController, bindingController, + listingController, + broadcastDispatcher, Optional.of(persistenceWrapper), dumpController ) assertTrue(controller.available) + verify(broadcastDispatcher).registerReceiver( + capture(broadcastReceiverCaptor), any(), any(), eq(UserHandle.ALL)) } private fun builderFromInfo(controlInfo: ControlInfo): Control.StatelessBuilder { @@ -115,6 +145,11 @@ class ControlsControllerImplTest : SysuiTestCase() { } @Test + fun testStartOnUser() { + assertEquals(user, controller.currentUserId) + } + + @Test fun testStartWithoutFavorites() { assertTrue(controller.getFavoriteControls().isEmpty()) } @@ -127,6 +162,8 @@ class ControlsControllerImplTest : SysuiTestCase() { delayableExecutor, uiController, bindingController, + listingController, + broadcastDispatcher, Optional.of(persistenceWrapper), dumpController ) @@ -190,7 +227,7 @@ class ControlsControllerImplTest : SysuiTestCase() { controller.loadForComponent(TEST_COMPONENT) {} reset(persistenceWrapper) - verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT), + verify(bindingController).bindAndLoad(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) controlLoadCallbackCaptor.value.invoke(listOf(control)) @@ -262,7 +299,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertEquals(ControlStatus(control, false), controlStatus) } - verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT), + verify(bindingController).bindAndLoad(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) controlLoadCallbackCaptor.value.invoke(listOf(control)) @@ -287,7 +324,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertEquals(ControlStatus(control2, false), controlStatus2) } - verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT), + verify(bindingController).bindAndLoad(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) controlLoadCallbackCaptor.value.invoke(listOf(control, control2)) @@ -309,7 +346,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertTrue(controlStatus.removed) } - verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT), + verify(bindingController).bindAndLoad(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) controlLoadCallbackCaptor.value.invoke(emptyList()) @@ -325,7 +362,7 @@ class ControlsControllerImplTest : SysuiTestCase() { controller.loadForComponent(TEST_COMPONENT) {} - verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT), + verify(bindingController).bindAndLoad(eq(TEST_COMPONENT), capture(controlLoadCallbackCaptor)) controlLoadCallbackCaptor.value.invoke(listOf(control)) @@ -358,4 +395,26 @@ class ControlsControllerImplTest : SysuiTestCase() { controller.clearFavorites() assertTrue(controller.getFavoriteControls().isEmpty()) } -} + + @Test + fun testSwitchUsers() { + controller.changeFavoriteStatus(TEST_CONTROL_INFO, true) + + reset(persistenceWrapper) + val intent = Intent(Intent.ACTION_USER_SWITCHED).apply { + putExtra(Intent.EXTRA_USER_HANDLE, otherUser) + } + val pendingResult = mock(BroadcastReceiver.PendingResult::class.java) + `when`(pendingResult.sendingUserId).thenReturn(otherUser) + broadcastReceiverCaptor.value.pendingResult = pendingResult + + broadcastReceiverCaptor.value.onReceive(mContext, intent) + + verify(persistenceWrapper).changeFile(any()) + verify(persistenceWrapper).readFavorites() + verify(bindingController).changeUser(UserHandle.of(otherUser)) + verify(listingController).changeUser(UserHandle.of(otherUser)) + assertTrue(controller.getFavoriteControls().isEmpty()) + assertEquals(otherUser, controller.currentUserId) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt index 4fc1cca76be6..40566dc39c9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.controls.controller import android.content.ComponentName +import android.os.UserHandle import android.service.controls.Control import android.service.controls.IControlsActionCallback import android.service.controls.IControlsLoadCallback @@ -86,6 +87,7 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { loadCallback, actionCallback, subscriber, + UserHandle.of(0), componentName ) } @@ -97,13 +99,13 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { @Test fun testBindService() { - manager.bindPermanently() + manager.bindService() assertTrue(mContext.isBound(componentName)) } @Test fun testUnbindService() { - manager.bindPermanently() + manager.bindService() manager.unbindService() assertFalse(mContext.isBound(componentName)) } @@ -123,7 +125,7 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { fun testMaybeUnbind_bindingAndCallback() { manager.maybeBindAndLoad {} - manager.maybeUnbindAndRemoveCallback() + manager.unbindService() assertFalse(mContext.isBound(componentName)) assertNull(manager.lastLoadCallback) } @@ -148,4 +150,4 @@ class ControlsProviderLifecycleManagerTest : SysuiTestCase() { eq(actionCallback)) assertEquals(action, wrapperCaptor.getValue().getWrappedAction()) } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt index f09aab97a219..85e937e40acd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt @@ -17,12 +17,15 @@ package com.android.systemui.controls.management import android.content.ComponentName +import android.content.Context +import android.content.ContextWrapper import android.content.pm.ServiceInfo +import android.os.UserHandle import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.settingslib.applications.ServiceListing -import com.android.settingslib.widget.CandidateInfo import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import org.junit.After @@ -69,13 +72,22 @@ class ControlsListingControllerImplTest : SysuiTestCase() { private var serviceListingCallbackCaptor = ArgumentCaptor.forClass(ServiceListing.Callback::class.java) + private val user = mContext.userId + private val otherUser = user + 1 + @Before fun setUp() { MockitoAnnotations.initMocks(this) `when`(serviceInfo.componentName).thenReturn(componentName) - controller = ControlsListingControllerImpl(mContext, executor, mockSL) + val wrapper = object : ContextWrapper(mContext) { + override fun createContextAsUser(user: UserHandle, flags: Int): Context { + return baseContext + } + } + + controller = ControlsListingControllerImpl(wrapper, executor, { mockSL }) verify(mockSL).addCallback(capture(serviceListingCallbackCaptor)) } @@ -86,6 +98,11 @@ class ControlsListingControllerImplTest : SysuiTestCase() { } @Test + fun testStartsOnUser() { + assertEquals(user, controller.currentUserId) + } + + @Test fun testNoServices_notListening() { assertTrue(controller.getCurrentServices().isEmpty()) } @@ -167,8 +184,9 @@ class ControlsListingControllerImplTest : SysuiTestCase() { controller.addCallback(mockCallbackOther) @Suppress("unchecked_cast") - val captor: ArgumentCaptor<List<CandidateInfo>> = - ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<CandidateInfo>> + val captor: ArgumentCaptor<List<ControlsServiceInfo>> = + ArgumentCaptor.forClass(List::class.java) + as ArgumentCaptor<List<ControlsServiceInfo>> executor.runAllReady() reset(mockCallback) @@ -185,4 +203,11 @@ class ControlsListingControllerImplTest : SysuiTestCase() { assertEquals(1, captor.value.size) assertEquals(componentName.flattenToString(), captor.value[0].key) } + + @Test + fun testChangeUser() { + controller.changeUser(UserHandle.of(otherUser)) + executor.runAllReady() + assertEquals(otherUser, controller.currentUserId) + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index 752e145d79bd..00d333fb593b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -53,6 +53,7 @@ public class DozeConfigurationUtil { when(config.pickupGestureEnabled(anyInt())).thenReturn(false); when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true); when(config.alwaysOnEnabled(anyInt())).thenReturn(false); + when(config.dozeSuppressed(anyInt())).thenReturn(false); when(config.enabled(anyInt())).thenReturn(true); when(config.getWakeLockScreenDebounce()).thenReturn(0L); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index f4cf314aa8fd..63cbca9255a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -139,6 +139,65 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); + + mMachine.requestState(INITIALIZED); + + verify(mPartMock).transitionTo(INITIALIZED, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test + public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); + + mMachine.requestState(INITIALIZED); + + verify(mPartMock).transitionTo(INITIALIZED, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test + public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mDockManager.isDocked()).thenReturn(true); + + mMachine.requestState(INITIALIZED); + + verify(mPartMock).transitionTo(INITIALIZED, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test + public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); + when(mDockManager.isDocked()).thenReturn(true); + when(mDockManager.isHidden()).thenReturn(true); + + mMachine.requestState(INITIALIZED); + + verify(mPartMock).transitionTo(INITIALIZED, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test + public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); + when(mDockManager.isDocked()).thenReturn(true); + when(mDockManager.isHidden()).thenReturn(true); + + mMachine.requestState(INITIALIZED); + + verify(mPartMock).transitionTo(INITIALIZED, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test public void testPulseDone_goesToDoze() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); @@ -165,6 +224,20 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testPulseDone_dozeSuppressed_goesToSuppressed() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); + mMachine.requestState(INITIALIZED); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestState(DOZE_PULSING); + + mMachine.requestState(DOZE_PULSE_DONE); + + verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test public void testPulseDone_afterDocked_goesToDockedAoD() { when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -178,6 +251,20 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mDockManager.isDocked()).thenReturn(true); + mMachine.requestState(INITIALIZED); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestState(DOZE_PULSING); + + mMachine.requestState(DOZE_PULSE_DONE); + + verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test public void testPulseDone_afterDockPaused_goesToDoze() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); @@ -193,6 +280,22 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() { + when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); + when(mDockManager.isDocked()).thenReturn(true); + when(mDockManager.isHidden()).thenReturn(true); + mMachine.requestState(INITIALIZED); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestState(DOZE_PULSING); + + mMachine.requestState(DOZE_PULSE_DONE); + + verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE); + assertEquals(DOZE, mMachine.getState()); + } + + @Test public void testFinished_staysFinished() { mMachine.requestState(INITIALIZED); mMachine.requestState(FINISH); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java new file mode 100644 index 000000000000..5bdca76d449c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java @@ -0,0 +1,77 @@ +/* + * 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.doze; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.hardware.display.AmbientDisplayConfiguration; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.doze.DozeSuppressedHandler.DozeSuppressedSettingObserver; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class DozeSuppressedHandlerTest extends SysuiTestCase { + @Mock private DozeMachine mMachine; + @Mock private DozeSuppressedSettingObserver mObserver; + private AmbientDisplayConfiguration mConfig; + private DozeSuppressedHandler mSuppressedHandler; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mConfig = DozeConfigurationUtil.createMockConfig(); + mSuppressedHandler = new DozeSuppressedHandler(mContext, mConfig, mMachine, mObserver); + } + + @Test + public void transitionTo_initialized_registersObserver() throws Exception { + mSuppressedHandler.transitionTo(DozeMachine.State.UNINITIALIZED, + DozeMachine.State.INITIALIZED); + + verify(mObserver).register(); + } + + @Test + public void transitionTo_finish_unregistersObserver() throws Exception { + mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED, + DozeMachine.State.FINISH); + + verify(mObserver).unregister(); + } + + @Test + public void transitionTo_doze_doesNothing() throws Exception { + mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED, + DozeMachine.State.DOZE); + + verify(mObserver, never()).register(); + verify(mObserver, never()).unregister(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index 47933ba9fdaa..e58a3a6bf5d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -16,8 +16,11 @@ package com.android.systemui.qs; import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.anyInt; 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.content.Context; @@ -447,6 +450,21 @@ public class QSSecurityFooterTest extends SysuiTestCase { view.findViewById(R.id.vpn_subtitle).getVisibility()); } + @Test + public void testNoClickWhenGone() { + QSTileHost mockHost = mock(QSTileHost.class); + mFooter.setHostEnvironment(mockHost); + mFooter.refreshState(); + + TestableLooper.get(this).processAllMessages(); + + assertFalse(mFooter.hasFooter()); + mFooter.onClick(mFooter.getView()); + + // Proxy for dialog being created + verify(mockHost, never()).collapsePanels(); + } + private CharSequence addLink(CharSequence description) { final SpannableStringBuilder message = new SpannableStringBuilder(); message.append(description); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index 9a7e97b5d55a..7c94ed20e95a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -17,9 +17,16 @@ package com.android.systemui.statusbar.notification.collection; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; +import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.service.notification.NotificationListenerService.REASON_CLICK; +import static android.service.notification.NotificationStats.DISMISSAL_SHADE; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; +import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; +import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -40,7 +47,6 @@ import static java.util.Objects.requireNonNull; import android.annotation.Nullable; import android.os.RemoteException; import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationStats; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; @@ -77,6 +83,7 @@ import org.mockito.Spy; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -139,9 +146,10 @@ public class NotifCollectionTest extends SysuiTestCase { .setRank(4747)); // THEN the listener is notified - verify(mCollectionListener).onEntryAdded(mEntryCaptor.capture()); - + verify(mCollectionListener).onEntryInit(mEntryCaptor.capture()); NotificationEntry entry = mEntryCaptor.getValue(); + + verify(mCollectionListener).onEntryAdded(entry); assertEquals(notif1.key, entry.getKey()); assertEquals(notif1.sbn, entry.getSbn()); assertEquals(notif1.ranking, entry.getRanking()); @@ -235,7 +243,8 @@ public class NotifCollectionTest extends SysuiTestCase { mNoMan.retractNotif(notif.sbn, REASON_APP_CANCEL); // THEN the listener is notified - verify(mCollectionListener).onEntryRemoved(entry, REASON_APP_CANCEL, false); + verify(mCollectionListener).onEntryRemoved(entry, REASON_APP_CANCEL); + verify(mCollectionListener).onEntryCleanUp(entry); assertEquals(notif.sbn, entry.getSbn()); assertEquals(notif.ranking, entry.getRanking()); } @@ -320,24 +329,15 @@ public class NotifCollectionTest extends SysuiTestCase { } @Test - public void testDismissNotification() throws RemoteException { - // GIVEN a collection with a couple notifications and a lifetime extender - mCollection.addNotificationLifetimeExtender(mExtender1); - + public void testDismissNotificationSentToSystemServer() throws RemoteException { + // GIVEN a collection with a couple notifications NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag")); NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag")); NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key); // WHEN a notification is manually dismissed - DismissedByUserStats stats = new DismissedByUserStats( - NotificationStats.DISMISSAL_SHADE, - NotificationStats.DISMISS_SENTIMENT_NEUTRAL, - NotificationVisibility.obtain(entry2.getKey(), 7, 2, true)); - - mCollection.dismissNotification(entry2, REASON_CLICK, stats); - - // THEN we check for lifetime extension - verify(mExtender1).shouldExtendLifetime(entry2, REASON_CLICK); + DismissedByUserStats stats = defaultStats(entry2); + mCollection.dismissNotification(entry2, defaultStats(entry2)); // THEN we send the dismissal to system server verify(mStatusBarService).onNotificationClear( @@ -349,9 +349,96 @@ public class NotifCollectionTest extends SysuiTestCase { stats.dismissalSurface, stats.dismissalSentiment, stats.notificationVisibility); + } + + @Test + public void testDismissedNotificationsAreMarkedAsDismissedLocally() { + // GIVEN a collection with a notification + NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag")); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN a notification is manually dismissed + mCollection.dismissNotification(entry1, defaultStats(entry1)); - // THEN we fire a remove event - verify(mCollectionListener).onEntryRemoved(entry2, REASON_CLICK, true); + // THEN the entry is marked as dismissed locally + assertEquals(DISMISSED, entry1.getDismissState()); + } + + @Test + public void testDismissedNotificationsCannotBeLifetimeExtended() { + // GIVEN a collection with a notification and a lifetime extender + mCollection.addNotificationLifetimeExtender(mExtender1); + NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag")); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN a notification is manually dismissed + mCollection.dismissNotification(entry1, defaultStats(entry1)); + + // THEN lifetime extenders are never queried + verify(mExtender1, never()).shouldExtendLifetime(eq(entry1), anyInt()); + } + + @Test + public void testDismissedNotificationsDoNotTriggerRemovalEvents() { + // GIVEN a collection with a notification + NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag")); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN a notification is manually dismissed + mCollection.dismissNotification(entry1, defaultStats(entry1)); + + // THEN onEntryRemoved is not called + verify(mCollectionListener, never()).onEntryRemoved(eq(entry1), anyInt()); + } + + @Test + public void testDismissedNotificationsStillAppearInNotificationSet() { + // GIVEN a collection with a notification + NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag")); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN a notification is manually dismissed + mCollection.dismissNotification(entry1, defaultStats(entry1)); + + // THEN the dismissed entry still appears in the notification set + assertEquals( + new ArraySet<>(Collections.singletonList(entry1)), + new ArraySet<>(mCollection.getActiveNotifs())); + } + + @Test + public void testDismissingLifetimeExtendedSummaryDoesNotDismissChildren() { + // GIVEN A notif group with one summary and two children + mCollection.addNotificationLifetimeExtender(mExtender1); + NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 1, "myTag") + .setGroup(mContext, GROUP_1) + .setGroupSummary(mContext, true)); + NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 2, "myTag") + .setGroup(mContext, GROUP_1)); + NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3, "myTag") + .setGroup(mContext, GROUP_1)); + + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key); + NotificationEntry entry3 = mCollectionListener.getEntry(notif3.key); + + // GIVEN that the summary and one child are retracted, but both are lifetime-extended + mExtender1.shouldExtendLifetime = true; + mNoMan.retractNotif(notif1.sbn, REASON_CANCEL); + mNoMan.retractNotif(notif2.sbn, REASON_CANCEL); + assertEquals( + new ArraySet<>(List.of(entry1, entry2, entry3)), + new ArraySet<>(mCollection.getActiveNotifs())); + + // WHEN the summary is dismissed by the user + mCollection.dismissNotification(entry1, defaultStats(entry1)); + + // THEN the summary is removed, but both children stick around + assertEquals( + new ArraySet<>(List.of(entry2, entry3)), + new ArraySet<>(mCollection.getActiveNotifs())); + assertEquals(NOT_DISMISSED, entry2.getDismissState()); + assertEquals(NOT_DISMISSED, entry3.getDismissState()); } @Test(expected = IllegalStateException.class) @@ -364,15 +451,115 @@ public class NotifCollectionTest extends SysuiTestCase { mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); // WHEN we try to dismiss a notification that isn't present - mCollection.dismissNotification( - entry2, - REASON_CLICK, - new DismissedByUserStats(0, 0, NotificationVisibility.obtain("foo", 47, 3, true))); + mCollection.dismissNotification(entry2, defaultStats(entry2)); // THEN an exception is thrown } @Test + public void testGroupChildrenAreDismissedLocallyWhenSummaryIsDismissed() { + // GIVEN a collection with two grouped notifs in it + NotifEvent notif0 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0) + .setGroup(mContext, GROUP_1) + .setGroupSummary(mContext, true)); + NotifEvent notif1 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 1) + .setGroup(mContext, GROUP_1)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN the summary is dismissed + mCollection.dismissNotification(entry0, defaultStats(entry0)); + + // THEN all members of the group are marked as dismissed locally + assertEquals(DISMISSED, entry0.getDismissState()); + assertEquals(PARENT_DISMISSED, entry1.getDismissState()); + } + + @Test + public void testUpdatingDismissedSummaryBringsChildrenBack() { + // GIVEN a collection with two grouped notifs in it + NotifEvent notif0 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0) + .setGroup(mContext, GROUP_1) + .setGroupSummary(mContext, true)); + NotifEvent notif1 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 1) + .setGroup(mContext, GROUP_1)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN the summary is dismissed but then reposted without a group + mCollection.dismissNotification(entry0, defaultStats(entry0)); + NotifEvent notif0a = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0)); + + // THEN it and all of its previous children are no longer dismissed locally + assertEquals(NOT_DISMISSED, entry0.getDismissState()); + assertEquals(NOT_DISMISSED, entry1.getDismissState()); + } + + @Test + public void testDismissedChildrenAreNotResetByParentUpdate() { + // GIVEN a collection with three grouped notifs in it + NotifEvent notif0 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0) + .setGroup(mContext, GROUP_1) + .setGroupSummary(mContext, true)); + NotifEvent notif1 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 1) + .setGroup(mContext, GROUP_1)); + NotifEvent notif2 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 2) + .setGroup(mContext, GROUP_1)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key); + + // WHEN a child is dismissed, then the parent is dismissed, then the parent is updated + mCollection.dismissNotification(entry1, defaultStats(entry1)); + mCollection.dismissNotification(entry0, defaultStats(entry0)); + NotifEvent notif0a = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0)); + + // THEN the manually-dismissed child is still marked as dismissed + assertEquals(NOT_DISMISSED, entry0.getDismissState()); + assertEquals(DISMISSED, entry1.getDismissState()); + assertEquals(NOT_DISMISSED, entry2.getDismissState()); + } + + @Test + public void testUpdatingGroupKeyOfDismissedSummaryBringsChildrenBack() { + // GIVEN a collection with two grouped notifs in it + NotifEvent notif0 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0) + .setOverrideGroupKey(GROUP_1) + .setGroupSummary(mContext, true)); + NotifEvent notif1 = mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 1) + .setOverrideGroupKey(GROUP_1)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key); + + // WHEN the summary is dismissed but then reposted AND in the same update one of the + // children's ranking loses its override group + mCollection.dismissNotification(entry0, defaultStats(entry0)); + mNoMan.setRanking(entry1.getKey(), new RankingBuilder() + .setKey(entry1.getKey()) + .build()); + mNoMan.postNotif( + buildNotif(TEST_PACKAGE, 0) + .setOverrideGroupKey(GROUP_1) + .setGroupSummary(mContext, true)); + + // THEN it and all of its previous children are no longer dismissed locally, including the + // child that is no longer part of the group + assertEquals(NOT_DISMISSED, entry0.getDismissState()); + assertEquals(NOT_DISMISSED, entry1.getDismissState()); + } + + @Test public void testLifetimeExtendersAreQueriedWhenNotifRemoved() { // GIVEN a couple notifications and a few lifetime extenders mExtender1.shouldExtendLifetime = true; @@ -387,12 +574,12 @@ public class NotifCollectionTest extends SysuiTestCase { NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key); // WHEN a notification is removed - mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); + mNoMan.retractNotif(notif2.sbn, REASON_CLICK); // THEN each extender is asked whether to extend, even if earlier ones return true - verify(mExtender1).shouldExtendLifetime(entry2, REASON_UNKNOWN); - verify(mExtender2).shouldExtendLifetime(entry2, REASON_UNKNOWN); - verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN); + verify(mExtender1).shouldExtendLifetime(entry2, REASON_CLICK); + verify(mExtender2).shouldExtendLifetime(entry2, REASON_CLICK); + verify(mExtender3).shouldExtendLifetime(entry2, REASON_CLICK); // THEN the entry is not removed assertTrue(mCollection.getActiveNotifs().contains(entry2)); @@ -426,9 +613,9 @@ public class NotifCollectionTest extends SysuiTestCase { mExtender2.callback.onEndLifetimeExtension(mExtender2, entry2); // THEN each extender is re-queried - verify(mExtender1).shouldExtendLifetime(entry2, REASON_UNKNOWN); - verify(mExtender2).shouldExtendLifetime(entry2, REASON_UNKNOWN); - verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN); + verify(mExtender1).shouldExtendLifetime(entry2, REASON_APP_CANCEL); + verify(mExtender2).shouldExtendLifetime(entry2, REASON_APP_CANCEL); + verify(mExtender3).shouldExtendLifetime(entry2, REASON_APP_CANCEL); // THEN the entry is not removed assertTrue(mCollection.getActiveNotifs().contains(entry2)); @@ -464,9 +651,9 @@ public class NotifCollectionTest extends SysuiTestCase { assertTrue(mCollection.getActiveNotifs().contains(entry2)); // THEN we don't re-query the extenders - verify(mExtender1, never()).shouldExtendLifetime(eq(entry2), anyInt()); - verify(mExtender2, never()).shouldExtendLifetime(eq(entry2), anyInt()); - verify(mExtender3, never()).shouldExtendLifetime(eq(entry2), anyInt()); + verify(mExtender1, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL); + verify(mExtender2, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL); + verify(mExtender3, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL); // THEN the entry properly records all extenders that returned true assertEquals(Arrays.asList(mExtender1), entry2.mLifetimeExtenders); @@ -499,7 +686,7 @@ public class NotifCollectionTest extends SysuiTestCase { // THEN the entry removed assertFalse(mCollection.getActiveNotifs().contains(entry2)); - verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN, false); + verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN); } @Test @@ -589,6 +776,36 @@ public class NotifCollectionTest extends SysuiTestCase { assertEquals(notif2a.ranking, entry2.getRanking()); } + @Test + public void testCancellationReasonIsSetWhenNotifIsCancelled() { + // GIVEN a notification + NotifEvent notif0 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + + // WHEN the notification is retracted + mNoMan.retractNotif(notif0.sbn, REASON_APP_CANCEL); + + // THEN the retraction reason is stored on the notif + assertEquals(REASON_APP_CANCEL, entry0.mCancellationReason); + } + + @Test + public void testCancellationReasonIsClearedWhenNotifIsUpdated() { + // GIVEN a notification and a lifetime extender that will preserve it + NotifEvent notif0 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)); + NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key); + mCollection.addNotificationLifetimeExtender(mExtender1); + mExtender1.shouldExtendLifetime = true; + + // WHEN the notification is retracted and subsequently reposted + mNoMan.retractNotif(notif0.sbn, REASON_APP_CANCEL); + assertEquals(REASON_APP_CANCEL, entry0.mCancellationReason); + mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)); + + // THEN the notification has its cancellation reason cleared + assertEquals(REASON_NOT_CANCELED, entry0.mCancellationReason); + } + private static NotificationEntryBuilder buildNotif(String pkg, int id, String tag) { return new NotificationEntryBuilder() .setPkg(pkg) @@ -602,10 +819,21 @@ public class NotifCollectionTest extends SysuiTestCase { .setId(id); } + private static DismissedByUserStats defaultStats(NotificationEntry entry) { + return new DismissedByUserStats( + DISMISSAL_SHADE, + DISMISS_SENTIMENT_NEUTRAL, + NotificationVisibility.obtain(entry.getKey(), 7, 2, true)); + } + private static class RecordingCollectionListener implements NotifCollectionListener { private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>(); @Override + public void onEntryInit(NotificationEntry entry) { + } + + @Override public void onEntryAdded(NotificationEntry entry) { mLastSeenEntries.put(entry.getKey(), entry); } @@ -615,7 +843,11 @@ public class NotifCollectionTest extends SysuiTestCase { } @Override - public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) { + public void onEntryRemoved(NotificationEntry entry, int reason) { + } + + @Override + public void onEntryCleanUp(NotificationEntry entry) { } public NotificationEntry getEntry(String key) { @@ -664,4 +896,6 @@ public class NotifCollectionTest extends SysuiTestCase { private static final String TEST_PACKAGE = "com.android.test.collection"; private static final String TEST_PACKAGE2 = "com.android.test.collection2"; + + private static final String GROUP_1 = "group_1"; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index dd896be0e120..b9d2d229cd69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -54,7 +54,6 @@ import com.android.systemui.statusbar.notification.NotificationInterruptionState import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -113,10 +112,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { notificationShadeWindowView, mock(NotificationListContainerViewGroup.class), mock(DozeScrimController.class), mock(ScrimController.class), mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), - mock(NotificationAlertingManager.class), - mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class), - mock(KeyguardIndicationController.class), - mStatusBar, mock(ShadeControllerImpl.class), mCommandQueue, mInitController); + mock(NotificationAlertingManager.class), mock(KeyguardStateController.class), + mock(KeyguardIndicationController.class), mStatusBar, + mock(ShadeControllerImpl.class), mCommandQueue, mInitController); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index e90e398ba061..db17a6e106b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -95,7 +95,6 @@ import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationListener; @@ -120,8 +119,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -133,10 +131,8 @@ import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.volume.VolumeComponent; @@ -149,7 +145,6 @@ import org.mockito.MockitoAnnotations; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.Optional; import javax.inject.Provider; @@ -166,7 +161,7 @@ public class StatusBarTest extends SysuiTestCase { private PowerManager mPowerManager; private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - @Mock private FeatureFlags mFeatureFlags; + @Mock private NotificationsController mNotificationsController; @Mock private LightBarController mLightBarController; @Mock private StatusBarIconController mStatusBarIconController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -180,7 +175,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private IDreamManager mDreamManager; @Mock private ScrimController mScrimController; @Mock private DozeScrimController mDozeScrimController; - @Mock private ArrayList<NotificationEntry> mNotificationList; @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; @Mock private BiometricUnlockController mBiometricUnlockController; @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; @@ -190,7 +184,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; - @Mock private RemoteInputUriController mRemoteInputUriController; @Mock private StatusBarStateControllerImpl mStatusBarStateController; @Mock private BatteryController mBatteryController; @Mock private DeviceProvisionedController mDeviceProvisionedController; @@ -214,8 +207,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private DynamicPrivacyController mDynamicPrivacyController; - @Mock private NotifPipelineInitializer mNewNotifPipeline; - @Mock private ZenModeController mZenModeController; @Mock private AutoHideController mAutoHideController; @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager; @Mock private UserSwitcherController mUserSwitcherController; @@ -223,7 +214,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private VibratorHelper mVibratorHelper; @Mock private BubbleController mBubbleController; @Mock private NotificationGroupManager mGroupManager; - @Mock private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController; @@ -247,7 +237,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ViewMediatorCallback mViewMediatorCallback; @Mock private DismissCallbackRegistry mDismissCallbackRegistry; @Mock private ScreenPinningRequest mScreenPinningRequest; - @Mock private NotificationEntryManager mEntryManager; @Mock private LockscreenLockIconController mLockscreenLockIconController; @Mock private StatusBarNotificationActivityStarter.Builder mStatusBarNotificationActivityStarterBuilder; @@ -256,7 +245,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardDismissUtil mKeyguardDismissUtil; @Mock private ExtensionController mExtensionController; @Mock private UserInfoControllerImpl mUserInfoControllerImpl; - @Mock private NotificationRowBinderImpl mNotificationRowBinder; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @@ -280,7 +268,7 @@ public class StatusBarTest extends SysuiTestCase { mMetricsLogger = new FakeMetricsLogger(); NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, - mUiBgExecutor, mEntryManager, mStatusBarStateController, + mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController, mExpansionStateLogger); notificationLogger.setVisibilityReporter(mock(Runnable.class)); @@ -334,7 +322,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar = new StatusBar( mContext, - mFeatureFlags, + mNotificationsController, mLightBarController, mAutoHideController, mKeyguardUpdateMonitor, @@ -346,7 +334,6 @@ public class StatusBarTest extends SysuiTestCase { mHeadsUpManager, mDynamicPrivacyController, mBypassHeadsUpNotifier, - () -> mNewNotifPipeline, new FalsingManagerFake(), mBroadcastDispatcher, new RemoteInputQuickSettingsDisabler( @@ -356,7 +343,6 @@ public class StatusBarTest extends SysuiTestCase { ), mNotificationGutsManager, notificationLogger, - mEntryManager, mNotificationInterruptionStateProvider, mNotificationViewHierarchyManager, mKeyguardViewMediator, @@ -377,12 +363,10 @@ public class StatusBarTest extends SysuiTestCase { mVibratorHelper, mBubbleController, mGroupManager, - mGroupAlertTransferHelper, mVisualStabilityManager, mDeviceProvisionedController, mNavigationBarController, () -> mAssistManager, - mNotificationListener, configurationController, mNotificationShadeWindowController, mLockscreenLockIconController, @@ -399,7 +383,6 @@ public class StatusBarTest extends SysuiTestCase { Optional.of(mRecents), mStatusBarComponentBuilderProvider, mPluginManager, - mRemoteInputUriController, Optional.of(mDivider), mLightsOutNotifController, mStatusBarNotificationActivityStarterBuilder, @@ -414,7 +397,6 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardDismissUtil, mExtensionController, mUserInfoControllerImpl, - mNotificationRowBinder, mDismissCallbackRegistry); when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn( @@ -675,7 +657,7 @@ public class StatusBarTest extends SysuiTestCase { public void testPanelOpenForHeadsUp() { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true); - when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); + when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true); mStatusBar.setBarStateForTest(StatusBarState.SHADE); @@ -693,7 +675,7 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testPanelOpenAndClear() { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); + when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); mStatusBar.setBarStateForTest(StatusBarState.SHADE); @@ -712,7 +694,7 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testPanelOpenAndNoClear() { when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false); - when(mEntryManager.getActiveNotificationsCount()).thenReturn(5); + when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5); when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false); mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index 5ac3b69549c1..667364c9c901 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -301,7 +301,7 @@ class EventDispatcher { * @param policyFlags The policy flags associated with the event. */ void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) { - int pointerIdBits = 0; + int pointerIdBits = prototype.getPointerIdBits(); final int pointerCount = prototype.getPointerCount(); for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); @@ -309,10 +309,10 @@ class EventDispatcher { if (!isInjectedPointerDown(pointerId)) { continue; } - pointerIdBits |= (1 << pointerId); - final int action = computeInjectionAction(MotionEvent.ACTION_UP, i); + final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i); sendMotionEvent( prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags); + pointerIdBits &= ~(1 << pointerId); } } } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 8eea04759cdb..507e98369855 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.metrics.LogMaker; @@ -187,7 +188,10 @@ final class SaveUi { context = new ContextThemeWrapper(context, mThemeId) { @Override public void startActivity(Intent intent) { - if (intent.resolveActivity(getPackageManager()) == null) { + if (resolveActivity(intent) == null) { + if (sDebug) { + Slog.d(TAG, "Can not startActivity for save UI with intent=" + intent); + } return; } intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true); @@ -199,6 +203,16 @@ final class SaveUi { // Apply restore mechanism startIntentSenderWithRestore(p, intent); } + + private ComponentName resolveActivity(Intent intent) { + final PackageManager packageManager = getPackageManager(); + final ComponentName componentName = intent.resolveActivity(packageManager); + if (componentName != null) { + return componentName; + } + intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL); + return intent.resolveActivity(packageManager); + } }; final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.autofill_save, null); diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java index dd1b84b16f68..7ea4eff3381c 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureMetricsLogger.java @@ -20,7 +20,8 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.service.contentcapture.FlushMetrics; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import java.util.List; @@ -35,8 +36,8 @@ public final class ContentCaptureMetricsLogger { /** @hide */ public static void writeServiceEvent(int eventType, @NonNull String serviceName, @Nullable String targetPackage) { - StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, eventType, serviceName, - targetPackage); + FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, eventType, + serviceName, targetPackage); } /** @hide */ @@ -79,16 +80,16 @@ public final class ContentCaptureMetricsLogger { stringBuilder.append(activities.get(i).flattenToShortString()); } } - StatsLog.write(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, - StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_WHITELIST, + FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS, + FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_WHITELIST, serviceName, stringBuilder.toString()); } /** @hide */ public static void writeSessionEvent(int sessionId, int event, int flags, @NonNull ComponentName service, @Nullable ComponentName app, boolean isChildSession) { - StatsLog.write(StatsLog.CONTENT_CAPTURE_SESSION_EVENTS, sessionId, event, flags, - ComponentName.flattenToShortString(service), + FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS, sessionId, event, + flags, ComponentName.flattenToShortString(service), ComponentName.flattenToShortString(app), isChildSession); } @@ -96,7 +97,7 @@ public final class ContentCaptureMetricsLogger { public static void writeSessionFlush(int sessionId, @NonNull ComponentName service, @Nullable ComponentName app, @NonNull FlushMetrics fm, @NonNull ContentCaptureOptions options, int flushReason) { - StatsLog.write(StatsLog.CONTENT_CAPTURE_FLUSHED, sessionId, + FrameworkStatsLog.write(FrameworkStatsLog.CONTENT_CAPTURE_FLUSHED, sessionId, ComponentName.flattenToShortString(service), ComponentName.flattenToShortString(app), fm.sessionStarted, fm.sessionFinished, fm.viewAppearedCount, fm.viewDisappearedCount, fm.viewTextChangedCount, diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 0f1122e3886a..583c5b593b88 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -61,13 +61,13 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.StatsLog; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.DataShareRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.contentcapture.RemoteContentCaptureService.ContentCaptureServiceCallbacks; import com.android.server.infra.AbstractPerUserSystemService; @@ -275,7 +275,7 @@ final class ContentCapturePerUserService /* binder= */ null); // Log metrics. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName, componentName, /* isChildSession= */ false); return; @@ -299,7 +299,7 @@ final class ContentCapturePerUserService /* binder= */ null); // Log metrics. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, STATE_DISABLED | STATE_NOT_WHITELISTED, serviceComponentName, componentName, /* isChildSession= */ false); return; @@ -313,7 +313,7 @@ final class ContentCapturePerUserService /* binder=*/ null); // Log metrics. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, STATE_DISABLED | STATE_DUPLICATED_ID, serviceComponentName, componentName, /* isChildSession= */ false); return; @@ -330,7 +330,7 @@ final class ContentCapturePerUserService /* binder= */ null); // Log metrics. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__SESSION_NOT_CREATED, STATE_DISABLED | STATE_NO_SERVICE, serviceComponentName, componentName, /* isChildSession= */ false); return; @@ -651,7 +651,7 @@ final class ContentCapturePerUserService } finally { Binder.restoreCallingIdentity(token); } - writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_DISABLED, + writeServiceEvent(FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__SET_DISABLED, getServiceComponentName()); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index c16df0f19943..9a170ac6da10 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -32,13 +32,13 @@ import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.IDataShareCallback; import android.service.contentcapture.SnapshotData; import android.util.Slog; -import android.util.StatsLog; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.DataShareRequest; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.FrameworkStatsLog; final class RemoteContentCaptureService extends AbstractMultiplePendingRequestsRemoteService<RemoteContentCaptureService, @@ -83,7 +83,8 @@ final class RemoteContentCaptureService if (connected) { try { mService.onConnected(mServerCallback, sVerbose, sDebug); - writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED, + writeServiceEvent( + FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_CONNECTED, mComponentName); } finally { // Update the system-service state, in case the service reconnected after @@ -92,7 +93,8 @@ final class RemoteContentCaptureService } } else { mService.onDisconnected(); - writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED, + writeServiceEvent( + FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_DISCONNECTED, mComponentName); } } catch (Exception e) { @@ -114,8 +116,9 @@ final class RemoteContentCaptureService (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState)); // Metrics logging. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED, initialState, - getComponentName(), context.getActivityComponent(), /* is_child_session= */ false); + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_STARTED, + initialState, getComponentName(), context.getActivityComponent(), + /* is_child_session= */ false); } /** @@ -126,7 +129,7 @@ final class RemoteContentCaptureService scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId)); // Metrics logging. writeSessionEvent(sessionId, - StatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED, + FrameworkStatsLog.CONTENT_CAPTURE_SESSION_EVENTS__EVENT__ON_SESSION_FINISHED, /* flags= */ 0, getComponentName(), /* app= */ null, /* is_child_session= */ false); } @@ -143,7 +146,8 @@ final class RemoteContentCaptureService */ public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request)); - writeServiceEvent(StatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_USER_DATA_REMOVED, + writeServiceEvent( + FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_USER_DATA_REMOVED, mComponentName); } diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java index a8be66990fff..5c2cbfa63a2b 100644 --- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -215,9 +215,14 @@ public abstract class UsageStatsManagerInternal { /** * Returns the events for the user in the given time period. + * + * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the + * result. + * @param hideShortcutInvocationEvents whether the {@link UsageEvents.Event#SHORTCUT_INVOCATION} + * events need to be excluded from the result. */ public abstract UsageEvents queryEventsForUser(@UserIdInt int userId, long beginTime, - long endTime, boolean shouldObfuscateInstantApps); + long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents); /** * Used to persist the last time a job was run for this app, in order to make decisions later diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 0f2fb9252c29..3441a5f19508 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -86,7 +86,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; -import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -94,6 +93,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocalLog; import com.android.internal.util.StatLogger; @@ -331,12 +331,16 @@ class AlarmManagerService extends SystemService { return (history == null) ? 0 : history.size(); } - long getLastWakeupForPackage(String packageName, int userId, int positionFromEnd) { + /** + * @param n The desired nth-last wakeup + * (1=1st-last=the ultimate wakeup and 2=2nd-last=the penultimate wakeup) + */ + long getNthLastWakeupForPackage(String packageName, int userId, int n) { final LongArrayQueue history = mPackageHistory.get(Pair.create(packageName, userId)); if (history == null) { return 0; } - final int i = history.size() - positionFromEnd; + final int i = history.size() - n; return (i < 0) ? 0 : history.get(i); } @@ -400,6 +404,11 @@ class AlarmManagerService extends SystemService { "standby_rare_quota", "standby_never_quota", }; + // Not putting this in the KEYS_APP_STANDBY_QUOTAS array because this uses a different + // window size. + private static final String KEY_APP_STANDBY_RESTRICTED_QUOTA = "standby_restricted_quota"; + private static final String KEY_APP_STANDBY_RESTRICTED_WINDOW = + "app_standby_restricted_window"; private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; @@ -420,6 +429,8 @@ class AlarmManagerService extends SystemService { 1, // Rare 0 // Never }; + private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1; + private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY; // Minimum futurity of a new alarm public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; @@ -446,6 +457,8 @@ class AlarmManagerService extends SystemService { public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW; public int[] APP_STANDBY_QUOTAS = new int[DEFAULT_APP_STANDBY_QUOTAS.length]; + public int APP_STANDBY_RESTRICTED_QUOTA = DEFAULT_APP_STANDBY_RESTRICTED_QUOTA; + public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -520,6 +533,14 @@ class AlarmManagerService extends SystemService { Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i])); } + APP_STANDBY_RESTRICTED_QUOTA = Math.max(1, + mParser.getInt(KEY_APP_STANDBY_RESTRICTED_QUOTA, + DEFAULT_APP_STANDBY_RESTRICTED_QUOTA)); + + APP_STANDBY_RESTRICTED_WINDOW = Math.max(APP_STANDBY_WINDOW, + mParser.getLong(KEY_APP_STANDBY_RESTRICTED_WINDOW, + DEFAULT_APP_STANDBY_RESTRICTED_WINDOW)); + MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID, DEFAULT_MAX_ALARMS_PER_UID); if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) { @@ -581,6 +602,14 @@ class AlarmManagerService extends SystemService { pw.println(APP_STANDBY_QUOTAS[i]); } + pw.print(KEY_APP_STANDBY_RESTRICTED_QUOTA); pw.print("="); + TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_QUOTA, pw); + pw.println(); + + pw.print(KEY_APP_STANDBY_RESTRICTED_WINDOW); pw.print("="); + TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_WINDOW, pw); + pw.println(); + pw.decreaseIndent(); } @@ -1814,25 +1843,44 @@ class AlarmManagerService extends SystemService { sourcePackage, sourceUserId, mInjector.getElapsedRealtime()); // Quota deferring implementation: + boolean deferred = false; final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage, sourceUserId); - final int quotaForBucket = getQuotaForBucketLocked(standbyBucket); - boolean deferred = false; - if (wakeupsInWindow >= quotaForBucket) { - final long minElapsed; - if (quotaForBucket <= 0) { - // Just keep deferring for a day till the quota changes - minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY; - } else { - // Suppose the quota for window was q, and the qth last delivery time for this - // package was t(q) then the next delivery must be after t(q) + <window_size> - final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage, - sourceUserId, quotaForBucket); - minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW; + if (standbyBucket == UsageStatsManager.STANDBY_BUCKET_RESTRICTED) { + // Special case because it's 1/day instead of 1/hour. + // AppWakeupHistory doesn't delete old wakeup times until a new one is logged, so we + // should always have the last wakeup available. + if (wakeupsInWindow > 0) { + final long lastWakeupTime = mAppWakeupHistory.getNthLastWakeupForPackage( + sourcePackage, sourceUserId, mConstants.APP_STANDBY_RESTRICTED_QUOTA); + if (mInjector.getElapsedRealtime() - lastWakeupTime + < mConstants.APP_STANDBY_RESTRICTED_WINDOW) { + final long minElapsed = + lastWakeupTime + mConstants.APP_STANDBY_RESTRICTED_WINDOW; + if (alarm.expectedWhenElapsed < minElapsed) { + alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed; + deferred = true; + } + } } - if (alarm.expectedWhenElapsed < minElapsed) { - alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed; - deferred = true; + } else { + final int quotaForBucket = getQuotaForBucketLocked(standbyBucket); + if (wakeupsInWindow >= quotaForBucket) { + final long minElapsed; + if (quotaForBucket <= 0) { + // Just keep deferring for a day till the quota changes + minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY; + } else { + // Suppose the quota for window was q, and the qth last delivery time for this + // package was t(q) then the next delivery must be after t(q) + <window_size> + final long t = mAppWakeupHistory.getNthLastWakeupForPackage( + sourcePackage, sourceUserId, quotaForBucket); + minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW; + } + if (alarm.expectedWhenElapsed < minElapsed) { + alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed; + deferred = true; + } } } if (!deferred) { @@ -3915,7 +3963,7 @@ class AlarmManagerService extends SystemService { Slog.v(TAG, "Time changed notification from kernel; rebatching"); } // StatsLog requires currentTimeMillis(), which == nowRTC to within usecs. - StatsLog.write(StatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC); + FrameworkStatsLog.write(FrameworkStatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC); removeImpl(null, mTimeTickTrigger); removeImpl(mDateChangeSender, null); rebatchAllAlarms(); diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 3774b645339d..311a494ee570 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -69,17 +69,17 @@ import android.text.TextUtils; import android.util.FeatureFlagUtils; import android.util.Log; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.pm.UserRestrictionsUtils; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.HashMap; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedList; import java.util.Locale; import java.util.Map; @@ -87,7 +87,6 @@ import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; - class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; @@ -2300,9 +2299,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { new ActiveLog(reason, packageName, enable, System.currentTimeMillis())); } - int state = enable ? StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED : - StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED; - StatsLog.write_non_chained(StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED, + int state = enable ? FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED : + FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED; + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED, Binder.getCallingUid(), null, state, reason, packageName); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2982dc9fab1b..8c8a4e22d48a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -557,13 +557,17 @@ public class ConnectivityService extends IConnectivityManager.Stub .asInterface(ServiceManager.getService("dnsresolver")); } - /** Handler thread used for both of the handlers below. */ + /** Handler thread used for all of the handlers below. */ @VisibleForTesting protected final HandlerThread mHandlerThread; /** Handler used for internal events. */ final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ final private NetworkStateTrackerHandler mTrackerHandler; + /** Handler used for processing {@link android.net.ConnectivityDiagnosticsManager} events */ + @VisibleForTesting + final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler; + private final DnsManager mDnsManager; private boolean mSystemReady; @@ -630,6 +634,10 @@ public class ConnectivityService extends IConnectivityManager.Stub @VisibleForTesting final MultipathPolicyTracker mMultipathPolicyTracker; + @VisibleForTesting + final Map<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo> + mConnectivityDiagnosticsCallbacks = new HashMap<>(); + /** * Implements support for the legacy "one network per network type" model. * @@ -962,6 +970,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandlerThread.start(); mHandler = new InternalHandler(mHandlerThread.getLooper()); mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper()); + mConnectivityDiagnosticsHandler = + new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper()); mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000); @@ -3391,18 +3401,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nri.unlinkDeathRecipient(); mNetworkRequests.remove(nri.request); - synchronized (mUidToNetworkRequestCount) { - int requests = mUidToNetworkRequestCount.get(nri.mUid, 0); - if (requests < 1) { - Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + - nri.mUid); - } else if (requests == 1) { - mUidToNetworkRequestCount.removeAt( - mUidToNetworkRequestCount.indexOfKey(nri.mUid)); - } else { - mUidToNetworkRequestCount.put(nri.mUid, requests - 1); - } - } + decrementNetworkRequestPerUidCount(nri); mNetworkRequestInfoLogs.log("RELEASE " + nri); if (nri.request.isRequest()) { @@ -3473,6 +3472,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) { + synchronized (mUidToNetworkRequestCount) { + final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0); + if (requests < 1) { + Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid); + } else if (requests == 1) { + mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid)); + } else { + mUidToNetworkRequestCount.put(nri.mUid, requests - 1); + } + } + } + @Override public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { enforceNetworkStackSettingsOrSetup(); @@ -4305,7 +4317,7 @@ public class ConnectivityService extends IConnectivityManager.Stub throwIfLockdownEnabled(); Vpn vpn = mVpns.get(userId); if (vpn != null) { - return vpn.prepare(oldPackage, newPackage); + return vpn.prepare(oldPackage, newPackage, false); } else { return false; } @@ -4354,6 +4366,78 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** + * Stores the given VPN profile based on the provisioning package name. + * + * <p>If there is already a VPN profile stored for the provisioning package, this call will + * overwrite the profile. + * + * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed + * exclusively by the Settings app, and passed into the platform at startup time. + * + * @return {@code true} if user consent has already been granted, {@code false} otherwise. + * @hide + */ + @Override + public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) { + final int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized (mVpns) { + return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore); + } + } + + /** + * Deletes the stored VPN profile for the provisioning package + * + * <p>If there are no profiles for the given package, this method will silently succeed. + * + * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed + * exclusively by the Settings app, and passed into the platform at startup time. + * + * @hide + */ + @Override + public void deleteVpnProfile(@NonNull String packageName) { + final int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized (mVpns) { + mVpns.get(user).deleteVpnProfile(packageName, mKeyStore); + } + } + + /** + * Starts the VPN based on the stored profile for the given package + * + * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed + * exclusively by the Settings app, and passed into the platform at startup time. + * + * @throws IllegalArgumentException if no profile was found for the given package name. + * @hide + */ + @Override + public void startVpnProfile(@NonNull String packageName) { + final int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized (mVpns) { + throwIfLockdownEnabled(); + mVpns.get(user).startVpnProfile(packageName, mKeyStore); + } + } + + /** + * Stops the Platform VPN if the provided package is running one. + * + * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed + * exclusively by the Settings app, and passed into the platform at startup time. + * + * @hide + */ + @Override + public void stopVpnProfile(@NonNull String packageName) { + final int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized (mVpns) { + mVpns.get(user).stopVpnProfile(packageName); + } + } + + /** * Start legacy VPN, controlling native daemons as needed. Creates a * secondary thread to perform connection work, returning quickly. */ @@ -4556,6 +4640,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Throws if there is any currently running, always-on Legacy VPN. + * + * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is + * running across the entire system. Tracking for app-based VPNs is done on a per-user, + * per-package basis in Vpn.java + */ @GuardedBy("mVpns") private void throwIfLockdownEnabled() { if (mLockdownEnabled) { @@ -5091,6 +5182,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + NetworkRequestInfo(NetworkRequest r) { + this(r, null); + } + private void enforceRequestCountLimit() { synchronized (mUidToNetworkRequestCount) { int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1; @@ -6165,7 +6260,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private void callCallbackForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType, int arg1) { if (nri.messenger == null) { - return; // Default request has no msgr + // Default request has no msgr. Also prevents callbacks from being invoked for + // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks + // are Type.LISTEN, but should not have NetworkCallbacks invoked. + return; } Bundle bundle = new Bundle(); // TODO: check if defensive copies of data is needed. @@ -6319,12 +6417,34 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + static class RequestReassignment { + @NonNull public final NetworkRequestInfo mRequest; + @Nullable public final NetworkAgentInfo mOldNetwork; + @Nullable public final NetworkAgentInfo mNewNetwork; + RequestReassignment(@NonNull final NetworkRequestInfo request, + @Nullable final NetworkAgentInfo oldNetwork, + @Nullable final NetworkAgentInfo newNetwork) { + mRequest = request; + mOldNetwork = oldNetwork; + mNewNetwork = newNetwork; + } + } + @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>(); + @NonNull private final List<RequestReassignment> mReassignments = new ArrayList<>(); @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() { return mRematchedNetworks; } + @NonNull Iterable<RequestReassignment> getRequestReassignments() { + return mReassignments; + } + + void addRequestReassignment(@NonNull final RequestReassignment reassignment) { + mReassignments.add(reassignment); + } + void addRematchedNetwork(@NonNull final NetworkBgStatePair network) { mRematchedNetworks.add(network); } @@ -6400,20 +6520,13 @@ public class ConnectivityService extends IConnectivityManager.Stub changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork, newNetwork.isBackgroundNetwork())); - final int score = newNetwork.getCurrentScore(); - if (VDBG || DDBG) log("rematching " + newNetwork.name()); final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = computeRequestReassignmentForNetwork(newNetwork); - NetworkCapabilities nc = newNetwork.networkCapabilities; - if (VDBG) log(" network has: " + nc); - // Find and migrate to this Network any NetworkRequests for // which this network is now the best. - final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>(); - final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>(); for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry : reassignedRequests.entrySet()) { final NetworkRequestInfo nri = entry.getKey(); @@ -6427,7 +6540,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } previousSatisfier.removeRequest(nri.request.requestId); previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs); - removedRequests.add(previousSatisfier); } else { if (VDBG || DDBG) log(" accepting network in place of null"); } @@ -6436,7 +6548,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!newSatisfier.addRequest(nri.request)) { Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request); } - addedRequests.add(nri); + changes.addRequestReassignment(new NetworkReassignment.RequestReassignment( + nri, previousSatisfier, newSatisfier)); // Tell NetworkProviders about the new score, so they can stop // trying to connect if they know they cannot match it. // TODO - this could get expensive if we have a lot of requests for this @@ -6493,21 +6606,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Have a new default network, release the transition wakelock in scheduleReleaseNetworkTransitionWakelock(); } - - if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) { - Slog.wtf(TAG, String.format( - "BUG: %s changed requestable capabilities during rematch: %s -> %s", - newNetwork.name(), nc, newNetwork.networkCapabilities)); - } - if (newNetwork.getCurrentScore() != score) { - Slog.wtf(TAG, String.format( - "BUG: %s changed score during rematch: %d -> %d", - newNetwork.name(), score, newNetwork.getCurrentScore())); - } - - // Notify requested networks are available after the default net is switched, but - // before LegacyTypeTracker sends legacy broadcasts - for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri); } /** @@ -6536,6 +6634,15 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork(); + // Notify requested networks are available after the default net is switched, but + // before LegacyTypeTracker sends legacy broadcasts + for (final NetworkReassignment.RequestReassignment event : + changes.getRequestReassignments()) { + if (null != event.mNewNetwork) { + notifyNetworkAvailable(event.mNewNetwork, event.mRequest); + } + } + for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) { // Process listen requests and update capabilities if the background state has // changed for this network. For consistency with previous behavior, send onLost @@ -7321,19 +7428,161 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Handler used for managing all Connectivity Diagnostics related functions. + * + * @see android.net.ConnectivityDiagnosticsManager + * + * TODO(b/147816404): Explore moving ConnectivityDiagnosticsHandler to a separate file + */ + @VisibleForTesting + class ConnectivityDiagnosticsHandler extends Handler { + /** + * Used to handle ConnectivityDiagnosticsCallback registration events from {@link + * android.net.ConnectivityDiagnosticsManager}. + * obj = ConnectivityDiagnosticsCallbackInfo with IConnectivityDiagnosticsCallback and + * NetworkRequestInfo to be registered + */ + private static final int EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 1; + + /** + * Used to handle ConnectivityDiagnosticsCallback unregister events from {@link + * android.net.ConnectivityDiagnosticsManager}. + * obj = the IConnectivityDiagnosticsCallback to be unregistered + * arg1 = the uid of the caller + */ + private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2; + + private ConnectivityDiagnosticsHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: { + handleRegisterConnectivityDiagnosticsCallback( + (ConnectivityDiagnosticsCallbackInfo) msg.obj); + break; + } + case EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: { + handleUnregisterConnectivityDiagnosticsCallback( + (IConnectivityDiagnosticsCallback) msg.obj, msg.arg1); + break; + } + } + } + } + + /** Class used for cleaning up IConnectivityDiagnosticsCallback instances after their death. */ + @VisibleForTesting + class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient { + @NonNull private final IConnectivityDiagnosticsCallback mCb; + @NonNull private final NetworkRequestInfo mRequestInfo; + + @VisibleForTesting + ConnectivityDiagnosticsCallbackInfo( + @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) { + mCb = cb; + mRequestInfo = nri; + } + + @Override + public void binderDied() { + log("ConnectivityDiagnosticsCallback IBinder died."); + unregisterConnectivityDiagnosticsCallback(mCb); + } + } + + private void handleRegisterConnectivityDiagnosticsCallback( + @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) { + ensureRunningOnConnectivityServiceThread(); + + final IConnectivityDiagnosticsCallback cb = cbInfo.mCb; + final NetworkRequestInfo nri = cbInfo.mRequestInfo; + + // This means that the client registered the same callback multiple times. Do + // not override the previous entry, and exit silently. + if (mConnectivityDiagnosticsCallbacks.containsKey(cb)) { + if (VDBG) log("Diagnostics callback is already registered"); + + // Decrement the reference count for this NetworkRequestInfo. The reference count is + // incremented when the NetworkRequestInfo is created as part of + // enforceRequestCountLimit(). + decrementNetworkRequestPerUidCount(nri); + return; + } + + mConnectivityDiagnosticsCallbacks.put(cb, cbInfo); + + try { + cb.asBinder().linkToDeath(cbInfo, 0); + } catch (RemoteException e) { + cbInfo.binderDied(); + } + } + + private void handleUnregisterConnectivityDiagnosticsCallback( + @NonNull IConnectivityDiagnosticsCallback cb, int uid) { + ensureRunningOnConnectivityServiceThread(); + + if (!mConnectivityDiagnosticsCallbacks.containsKey(cb)) { + if (VDBG) log("Removing diagnostics callback that is not currently registered"); + return; + } + + final NetworkRequestInfo nri = mConnectivityDiagnosticsCallbacks.get(cb).mRequestInfo; + + if (uid != nri.mUid) { + if (VDBG) loge("Different uid than registrant attempting to unregister cb"); + return; + } + + cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0); + } + @Override public void registerConnectivityDiagnosticsCallback( @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) { - // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality - throw new UnsupportedOperationException( - "registerConnectivityDiagnosticsCallback not yet implemented"); + if (request.legacyType != TYPE_NONE) { + throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated." + + " Please use NetworkCapabilities instead."); + } + + // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid + // and administrator uids to be safe. + final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities); + restrictRequestUidsForCaller(nc); + + final NetworkRequest requestWithId = + new NetworkRequest( + nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); + + // NetworkRequestInfos created here count towards MAX_NETWORK_REQUESTS_PER_UID limit. + // + // nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in + // handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the + // callback's binder death. + final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId); + final ConnectivityDiagnosticsCallbackInfo cbInfo = + new ConnectivityDiagnosticsCallbackInfo(callback, nri); + + mConnectivityDiagnosticsHandler.sendMessage( + mConnectivityDiagnosticsHandler.obtainMessage( + ConnectivityDiagnosticsHandler + .EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK, + cbInfo)); } @Override public void unregisterConnectivityDiagnosticsCallback( @NonNull IConnectivityDiagnosticsCallback callback) { - // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality - throw new UnsupportedOperationException( - "unregisterConnectivityDiagnosticsCallback not yet implemented"); + mConnectivityDiagnosticsHandler.sendMessage( + mConnectivityDiagnosticsHandler.obtainMessage( + ConnectivityDiagnosticsHandler + .EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK, + Binder.getCallingUid(), + 0, + callback)); } } diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index bacffb6140ed..80036bb4b4fa 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -42,11 +42,11 @@ import android.util.ExceptionUtils; import android.util.Log; import android.util.MathUtils; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; @@ -253,7 +253,7 @@ public class RescueParty { private static void executeRescueLevelInternal(Context context, int level, @Nullable String failedPackage) throws Exception { - StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level); + FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level); switch (level) { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage); @@ -393,8 +393,8 @@ public class RescueParty { @Override public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage, @FailureReasons int failureReason) { - if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH - || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) { + if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH + || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) { return mapRescueLevelToUserImpact(getNextRescueLevel()); } else { return PackageHealthObserverImpact.USER_IMPACT_NONE; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index e17dde9a766e..a08bdb23dd22 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3942,8 +3942,12 @@ class StorageManagerService extends IStorageManager.Stub final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) == PERMISSION_GRANTED; if (mIsFuseEnabled && hasMtp) { - // The process hosting the MTP server should be able to write in Android/ - return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName, + 0, UserHandle.getUserId(uid)); + if (ai.isSignedWithPlatformKey()) { + // Platform processes hosting the MTP server should be able to write in Android/ + return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + } } // Determine if caller is holding runtime permission diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 139a87154223..56f942480eaf 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -77,7 +77,6 @@ import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.LocalLog; -import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; @@ -87,6 +86,7 @@ import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; @@ -2395,12 +2395,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (state == TelephonyManager.CALL_STATE_IDLE) { mBatteryStats.notePhoneOff(); - StatsLog.write(StatsLog.PHONE_STATE_CHANGED, - StatsLog.PHONE_STATE_CHANGED__STATE__OFF); + FrameworkStatsLog.write(FrameworkStatsLog.PHONE_STATE_CHANGED, + FrameworkStatsLog.PHONE_STATE_CHANGED__STATE__OFF); } else { mBatteryStats.notePhoneOn(); - StatsLog.write(StatsLog.PHONE_STATE_CHANGED, - StatsLog.PHONE_STATE_CHANGED__STATE__ON); + FrameworkStatsLog.write(FrameworkStatsLog.PHONE_STATE_CHANGED, + FrameworkStatsLog.PHONE_STATE_CHANGED__STATE__ON); } } catch (RemoteException e) { /* The remote entity disappeared, we can safely ignore the exception. */ diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 6bc090a4f7ba..79b3a7b0d114 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -66,6 +66,7 @@ import android.util.DebugUtils; import android.util.Slog; import android.util.SparseArray; import android.util.StatsLog; +import android.util.proto.ProtoOutputStream; import android.view.InputDevice; import com.android.internal.annotations.GuardedBy; @@ -165,6 +166,7 @@ public class VibratorService extends IVibratorService.Stub private ExternalVibration mCurrentExternalVibration; private boolean mVibratorUnderExternalControl; private boolean mLowPowerMode; + private boolean mIsVibrating; private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; @@ -327,6 +329,14 @@ public class VibratorService extends IVibratorService.Stub .append(mReason) .toString(); } + + void dumpProto(ProtoOutputStream proto, long fieldId) { + synchronized (this) { + final long token = proto.start(fieldId); + proto.write(VibrationProto.START_TIME, mStartTimeDebug); + proto.end(token); + } + } } private static final class ScaleLevel { @@ -1363,6 +1373,7 @@ public class VibratorService extends IVibratorService.Stub StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null, StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis); mCurVibUid = uid; + mIsVibrating = true; } catch (RemoteException e) { } } @@ -1376,6 +1387,7 @@ public class VibratorService extends IVibratorService.Stub } catch (RemoteException e) { } mCurVibUid = -1; } + mIsVibrating = false; } private void setVibratorUnderExternalControl(boolean externalControl) { @@ -1390,6 +1402,93 @@ public class VibratorService extends IVibratorService.Stub vibratorSetExternalControl(externalControl); } + private void dumpInternal(PrintWriter pw) { + pw.println("Vibrator Service:"); + synchronized (mLock) { + pw.print(" mCurrentVibration="); + if (mCurrentVibration != null) { + pw.println(mCurrentVibration.toInfo().toString()); + } else { + pw.println("null"); + } + pw.print(" mCurrentExternalVibration=" + mCurrentExternalVibration); + pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl); + pw.println(" mIsVibrating=" + mIsVibrating); + pw.println(" mLowPowerMode=" + mLowPowerMode); + pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity); + pw.println(" mNotificationIntensity=" + mNotificationIntensity); + pw.println(" mRingIntensity=" + mRingIntensity); + pw.println(" mSupportedEffects=" + mSupportedEffects); + pw.println(); + pw.println(" Previous ring vibrations:"); + for (VibrationInfo info : mPreviousRingVibrations) { + pw.print(" "); + pw.println(info.toString()); + } + + pw.println(" Previous notification vibrations:"); + for (VibrationInfo info : mPreviousNotificationVibrations) { + pw.println(" " + info); + } + + pw.println(" Previous alarm vibrations:"); + for (VibrationInfo info : mPreviousAlarmVibrations) { + pw.println(" " + info); + } + + pw.println(" Previous vibrations:"); + for (VibrationInfo info : mPreviousVibrations) { + pw.println(" " + info); + } + + pw.println(" Previous external vibrations:"); + for (ExternalVibration vib : mPreviousExternalVibrations) { + pw.println(" " + vib); + } + } + } + + private void dumpProto(FileDescriptor fd) { + final ProtoOutputStream proto = new ProtoOutputStream(fd); + + synchronized (mLock) { + if (mCurrentVibration != null) { + mCurrentVibration.toInfo().dumpProto(proto, + VibratorServiceDumpProto.CURRENT_VIBRATION); + } + proto.write(VibratorServiceDumpProto.IS_VIBRATING, mIsVibrating); + proto.write(VibratorServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL, + mVibratorUnderExternalControl); + proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode); + proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY, + mHapticFeedbackIntensity); + proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY, + mNotificationIntensity); + proto.write(VibratorServiceDumpProto.RING_INTENSITY, mRingIntensity); + + for (VibrationInfo info : mPreviousRingVibrations) { + info.dumpProto(proto, + VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS); + } + + for (VibrationInfo info : mPreviousNotificationVibrations) { + info.dumpProto(proto, + VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS); + } + + for (VibrationInfo info : mPreviousAlarmVibrations) { + info.dumpProto(proto, + VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS); + } + + for (VibrationInfo info : mPreviousVibrations) { + info.dumpProto(proto, + VibratorServiceDumpProto.PREVIOUS_VIBRATIONS); + } + } + proto.flush(); + } + private class VibrateThread extends Thread { private final VibrationEffect.Waveform mWaveform; private final int mUid; @@ -1556,47 +1655,22 @@ public class VibratorService extends IVibratorService.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - pw.println("Vibrator Service:"); - synchronized (mLock) { - pw.print(" mCurrentVibration="); - if (mCurrentVibration != null) { - pw.println(mCurrentVibration.toInfo().toString()); - } else { - pw.println("null"); - } - pw.print(" mCurrentExternalVibration=" + mCurrentExternalVibration); - pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl); - pw.println(" mLowPowerMode=" + mLowPowerMode); - pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity); - pw.println(" mNotificationIntensity=" + mNotificationIntensity); - pw.println(" mRingIntensity=" + mRingIntensity); - pw.println(" mSupportedEffects=" + mSupportedEffects); - pw.println(); - pw.println(" Previous ring vibrations:"); - for (VibrationInfo info : mPreviousRingVibrations) { - pw.print(" "); - pw.println(info.toString()); - } - - pw.println(" Previous notification vibrations:"); - for (VibrationInfo info : mPreviousNotificationVibrations) { - pw.println(" " + info); - } + final long ident = Binder.clearCallingIdentity(); - pw.println(" Previous alarm vibrations:"); - for (VibrationInfo info : mPreviousAlarmVibrations) { - pw.println(" " + info); + boolean isDumpProto = false; + for (String arg : args) { + if (arg.equals("--proto")) { + isDumpProto = true; } - - pw.println(" Previous vibrations:"); - for (VibrationInfo info : mPreviousVibrations) { - pw.println(" " + info); - } - - pw.println(" Previous external vibrations:"); - for (ExternalVibration vib : mPreviousExternalVibrations) { - pw.println(" " + vib); + } + try { + if (isDumpProto) { + dumpProto(fd); + } else { + dumpInternal(pw); } + } finally { + Binder.restoreCallingIdentity(ident); } } diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index a60b09fda2e8..a1ccd8459c69 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -40,10 +40,10 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; -import android.util.StatsLog; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.ZygoteConnectionConstants; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.am.ActivityManagerService; import com.android.server.wm.SurfaceAnimationThread; @@ -636,7 +636,8 @@ public class Watchdog extends Thread { "watchdog", null, "system_server", null, null, null, subject, cpuInfo, stack, null); } - StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject); + FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, + subject); } }; dropboxThread.start(); diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 143474bd5c94..10994133e265 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -46,12 +46,12 @@ import android.service.adb.AdbDebuggingManagerProto; import android.util.AtomicFile; import android.util.Base64; import android.util.Slog; -import android.util.StatsLog; import android.util.Xml; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.FgThread; @@ -493,8 +493,8 @@ public class AdbDebuggingManager { "Logging key " + key + ", state = " + state + ", alwaysAllow = " + alwaysAllow + ", lastConnectionTime = " + lastConnectionTime + ", authWindow = " + authWindow); - StatsLog.write(StatsLog.ADB_CONNECTION_CHANGED, lastConnectionTime, authWindow, state, - alwaysAllow); + FrameworkStatsLog.write(FrameworkStatsLog.ADB_CONNECTION_CHANGED, lastConnectionTime, + authWindow, state, alwaysAllow); } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index c5d6bba27234..c75ee04543e3 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -130,6 +130,10 @@ class UserController implements Handler.Callback { // giving up on them and unfreezing the screen. static final int USER_SWITCH_TIMEOUT_MS = 3 * 1000; + // Amount of time we wait for observers to handle a user switch before we log a warning. + // Must be smaller than USER_SWITCH_TIMEOUT_MS. + private static final int USER_SWITCH_WARNING_TIMEOUT_MS = 500; + // ActivityManager thread message constants static final int REPORT_USER_SWITCH_MSG = 10; static final int CONTINUE_USER_SWITCH_MSG = 20; @@ -1615,9 +1619,13 @@ class UserController implements Handler.Callback { synchronized (mLock) { long delay = SystemClock.elapsedRealtime() - dispatchStartedTime; if (delay > USER_SWITCH_TIMEOUT_MS) { - Slog.e(TAG, "User switch timeout: observer " + name + Slog.e(TAG, "User switch timeout: observer " + name + " sent result after " + delay + " ms"); + } else if (delay > USER_SWITCH_WARNING_TIMEOUT_MS) { + Slog.w(TAG, "User switch slowed down by observer " + name + + ": result sent after " + delay + " ms"); } + curWaitingUserSwitchCallbacks.remove(name); // Continue switching if all callbacks have been notified and // user switching session is still valid diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 5ac5b29b1475..0440de674e9e 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -56,13 +56,12 @@ import android.service.attention.IAttentionService; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Preconditions; import com.android.server.SystemService; import java.io.FileDescriptor; @@ -274,8 +273,8 @@ public class AttentionManagerService extends SystemService { userState.mAttentionCheckCacheBuffer.add( new AttentionCheckCache(SystemClock.uptimeMillis(), result, timestamp)); } - StatsLog.write( - StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, + FrameworkStatsLog.write( + FrameworkStatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, result); } @@ -287,8 +286,8 @@ public class AttentionManagerService extends SystemService { userState.mCurrentAttentionCheck.mIsFulfilled = true; } - StatsLog.write( - StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, + FrameworkStatsLog.write( + FrameworkStatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, error); } }; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8f6bd212da19..b2548af0f576 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1068,6 +1068,27 @@ public class AudioService extends IAudioService.Stub } } + // Restore capture policies + synchronized (mPlaybackMonitor) { + HashMap<Integer, Integer> allowedCapturePolicies = + mPlaybackMonitor.getAllAllowedCapturePolicies(); + for (HashMap.Entry<Integer, Integer> entry : allowedCapturePolicies.entrySet()) { + int result = AudioSystem.setAllowedCapturePolicy( + entry.getKey(), + AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0)); + if (result != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Failed to restore capture policy, uid: " + + entry.getKey() + ", capture policy: " + entry.getValue() + + ", result: " + result); + // When restoring capture policy failed, set the capture policy as + // ALLOW_CAPTURE_BY_ALL, which will result in removing the cached + // capture policy in PlaybackActivityMonitor. + mPlaybackMonitor.setAllowedCapturePolicy( + entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + } + } + onIndicateSystemReady(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); @@ -7298,6 +7319,43 @@ public class AudioService extends IAudioService.Stub mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid()); } + /** + * Specifies whether the audio played by this app may or may not be captured by other apps or + * the system. + * + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + * @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed. + * @throws IllegalArgumentException if the argument is not a valid value. + */ + public int setAllowedCapturePolicy(int capturePolicy) { + int callingUid = Binder.getCallingUid(); + int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0); + final long identity = Binder.clearCallingIdentity(); + synchronized (mPlaybackMonitor) { + int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags); + if (result == AudioSystem.AUDIO_STATUS_OK) { + mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy); + } + Binder.restoreCallingIdentity(identity); + return result; + } + } + + /** + * Return the capture policy. + * @return the cached capture policy for the calling uid. + */ + public int getAllowedCapturePolicy() { + int callingUid = Binder.getCallingUid(); + final long identity = Binder.clearCallingIdentity(); + int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid); + Binder.restoreCallingIdentity(identity); + return capturePolicy; + } + //====================== // Audio device management //====================== diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index f8ba55bcd092..98f409ea98e7 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor new AudioPlaybackConfiguration(pic, newPiid, Binder.getCallingUid(), Binder.getCallingPid()); apc.init(); + synchronized (mAllowedCapturePolicies) { + int uid = apc.getClientUid(); + if (mAllowedCapturePolicies.containsKey(uid)) { + updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); + } + } sEventLogger.log(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); @@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { final boolean change; + synchronized (mAllowedCapturePolicies) { + if (mAllowedCapturePolicies.containsKey(binderUid) + && attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) { + attr = new AudioAttributes.Builder(attr) + .setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build(); + } + } synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { @@ -284,6 +297,69 @@ public final class PlaybackActivityMonitor } } + /** + * A map of uid to capture policy. + */ + private final HashMap<Integer, Integer> mAllowedCapturePolicies = + new HashMap<Integer, Integer>(); + + /** + * Cache allowed capture policy, which specifies whether the audio played by the app may or may + * not be captured by other apps or the system. + * + * @param uid the uid of requested app + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + */ + public void setAllowedCapturePolicy(int uid, int capturePolicy) { + synchronized (mAllowedCapturePolicies) { + if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) { + // When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to + // remove it from cached capture policy as it is the default value. + mAllowedCapturePolicies.remove(uid); + return; + } else { + mAllowedCapturePolicies.put(uid, capturePolicy); + } + } + synchronized (mPlayerLock) { + for (AudioPlaybackConfiguration apc : mPlayers.values()) { + if (apc.getClientUid() == uid) { + updateAllowedCapturePolicy(apc, capturePolicy); + } + } + } + } + + /** + * Return the capture policy for given uid. + * @param uid the uid to query its cached capture policy. + * @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL + * if there is not cached capture policy. + */ + public int getAllowedCapturePolicy(int uid) { + return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + + /** + * Return all cached capture policies. + */ + public HashMap<Integer, Integer> getAllAllowedCapturePolicies() { + return mAllowedCapturePolicies; + } + + private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) { + AudioAttributes attr = apc.getAudioAttributes(); + if (attr.getAllowedCapturePolicy() >= capturePolicy) { + return; + } + apc.handleAudioAttributesEvent( + new AudioAttributes.Builder(apc.getAudioAttributes()) + .setAllowedCapturePolicy(capturePolicy).build()); + } + // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor @Override public void playerDeath(int piid) { @@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor // log sEventLogger.dump(pw); } + synchronized (mAllowedCapturePolicies) { + pw.println("\n allowed capture policies:"); + for (HashMap.Entry<Integer, Integer> entry : mAllowedCapturePolicies.entrySet()) { + pw.println(" uid: " + entry.getKey() + " policy: " + entry.getValue()); + } + } } /** diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 96af74a60b1d..61c99b88d113 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -36,23 +36,22 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.wm.WindowManagerInternal; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * CameraServiceProxy is the system_server analog to the camera service running in cameraserver. @@ -315,22 +314,22 @@ public class CameraServiceProxy extends SystemService * Package-private */ private void logCameraUsageEvent(CameraUsageEvent e) { - int facing = StatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN; + int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN; switch(e.mCameraFacing) { case ICameraServiceProxy.CAMERA_FACING_BACK: - facing = StatsLog.CAMERA_ACTION_EVENT__FACING__BACK; + facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK; break; case ICameraServiceProxy.CAMERA_FACING_FRONT: - facing = StatsLog.CAMERA_ACTION_EVENT__FACING__FRONT; + facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT; break; case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: - facing = StatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL; + facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL; break; default: Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing); } - StatsLog.write(StatsLog.CAMERA_ACTION_EVENT, e.getDuration(), e.mAPILevel, - e.mClientName, facing); + FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, e.getDuration(), + e.mAPILevel, e.mClientName, facing); } } diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index bb8b12e86e16..2fc9d04623f8 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -25,7 +25,6 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.AndroidBuildClassifier; @@ -54,7 +53,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { public PlatformCompat(Context context) { mContext = context; mChangeReporter = new ChangeReporter( - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); } @@ -62,14 +61,14 @@ public class PlatformCompat extends IPlatformCompat.Stub { PlatformCompat(Context context, CompatConfig compatConfig) { mContext = context; mChangeReporter = new ChangeReporter( - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = compatConfig; } @Override public void reportChange(long changeId, ApplicationInfo appInfo) { reportChange(changeId, appInfo.uid, - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + ChangeReporter.STATE_LOGGED); } @Override @@ -83,18 +82,18 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public void reportChangeByUid(long changeId, int uid) { - reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + reportChange(changeId, uid, ChangeReporter.STATE_LOGGED); } @Override public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) { if (mCompatConfig.isChangeEnabled(changeId, appInfo)) { reportChange(changeId, appInfo.uid, - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); + ChangeReporter.STATE_ENABLED); return true; } reportChange(changeId, appInfo.uid, - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED); + ChangeReporter.STATE_DISABLED); return false; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 423e0212dfd6..03795597f47a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -24,6 +24,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -157,6 +159,16 @@ public class Vpn { // is actually O(n²)+O(n²). private static final int MAX_ROUTES_TO_EVALUATE = 150; + /** + * Largest profile size allowable for Platform VPNs. + * + * <p>The largest platform VPN profiles use IKEv2 RSA Certificate Authentication and have two + * X509Certificates, and one RSAPrivateKey. This should lead to a max size of 2x 12kB for the + * certificates, plus a reasonable upper bound on the private key of 32kB. The rest of the + * profile is expected to be negligible in size. + */ + @VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB + // TODO: create separate trackers for each unique VPN to support // automated reconnection @@ -656,6 +668,11 @@ public class Vpn { * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and * it can be revoked by itself. * + * The permission checks to verify that the VPN has already been granted + * user consent are dependent on the type of the VPN being prepared. See + * {@link AppOpsManager#OP_ACTIVATE_VPN} and {@link + * AppOpsManager#OP_ACTIVATE_PLATFORM_VPN} for more information. + * * Note: when we added VPN pre-consent in * https://android.googlesource.com/platform/frameworks/base/+/0554260 * the names oldPackage and newPackage became misleading, because when @@ -674,10 +691,13 @@ public class Vpn { * * @param oldPackage The package name of the old VPN application * @param newPackage The package name of the new VPN application - * + * @param isPlatformVpn Whether the package being prepared is using a platform VPN profile. + * Preparing a platform VPN profile requires only the lesser ACTIVATE_PLATFORM_VPN appop. * @return true if the operation succeeded. */ - public synchronized boolean prepare(String oldPackage, String newPackage) { + // TODO: Use an Intdef'd type to represent what kind of VPN the caller is preparing. + public synchronized boolean prepare( + String oldPackage, String newPackage, boolean isPlatformVpn) { if (oldPackage != null) { // Stop an existing always-on VPN from being dethroned by other apps. if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) { @@ -688,13 +708,14 @@ public class Vpn { if (!isCurrentPreparedPackage(oldPackage)) { // The package doesn't match. We return false (to obtain user consent) unless the // user has already consented to that VPN package. - if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { + if (!oldPackage.equals(VpnConfig.LEGACY_VPN) + && isVpnPreConsented(mContext, oldPackage, isPlatformVpn)) { prepareInternal(oldPackage); return true; } return false; } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) - && !isVpnUserPreConsented(oldPackage)) { + && !isVpnPreConsented(mContext, oldPackage, isPlatformVpn)) { // Currently prepared VPN is revoked, so unprepare it and return false. prepareInternal(VpnConfig.LEGACY_VPN); return false; @@ -805,13 +826,29 @@ public class Vpn { return false; } - private boolean isVpnUserPreConsented(String packageName) { - AppOpsManager appOps = - (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + private static boolean isVpnPreConsented( + Context context, String packageName, boolean isPlatformVpn) { + return isPlatformVpn + ? isVpnProfilePreConsented(context, packageName) + : isVpnServicePreConsented(context, packageName); + } - // Verify that the caller matches the given package and has permission to activate VPNs. - return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(), - packageName) == AppOpsManager.MODE_ALLOWED; + private static boolean doesPackageHaveAppop(Context context, String packageName, int appop) { + final AppOpsManager appOps = + (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + + // Verify that the caller matches the given package and has the required permission. + return appOps.noteOpNoThrow(appop, Binder.getCallingUid(), packageName) + == AppOpsManager.MODE_ALLOWED; + } + + private static boolean isVpnServicePreConsented(Context context, String packageName) { + return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_VPN); + } + + private static boolean isVpnProfilePreConsented(Context context, String packageName) { + return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN) + || isVpnServicePreConsented(context, packageName); } private int getAppUid(String app, int userHandle) { @@ -1005,6 +1042,9 @@ public class Vpn { * Establish a VPN network and return the file descriptor of the VPN interface. This methods * returns {@code null} if the application is revoked or not prepared. * + * <p>This method supports ONLY VpnService-based VPNs. For Platform VPNs, see {@link + * provisionVpnProfile} and {@link startVpnProfile} + * * @param config The parameters to configure the network. * @return The file descriptor of the VPN interface. */ @@ -1015,7 +1055,7 @@ public class Vpn { return null; } // Check to ensure consent hasn't been revoked since we were prepared. - if (!isVpnUserPreConsented(mPackage)) { + if (!isVpnServicePreConsented(mContext, mPackage)) { return null; } // Check if the service is properly declared. @@ -1680,6 +1720,10 @@ public class Vpn { public int settingsSecureGetIntForUser(String key, int def, int userId) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId); } + + public boolean isCallerSystem() { + return Binder.getCallingUid() == Process.SYSTEM_UID; + } } private native int jniCreate(int mtu); @@ -2228,4 +2272,148 @@ public class Vpn { } } } + + private void verifyCallingUidAndPackage(String packageName) { + if (getAppUid(packageName, mUserHandle) != Binder.getCallingUid()) { + throw new SecurityException("Mismatched package and UID"); + } + } + + @VisibleForTesting + String getProfileNameForPackage(String packageName) { + return Credentials.PLATFORM_VPN + mUserHandle + "_" + packageName; + } + + /** + * Stores an app-provisioned VPN profile and returns whether the app is already prepared. + * + * @param packageName the package name of the app provisioning this profile + * @param profile the profile to be stored and provisioned + * @param keyStore the System keystore instance to save VPN profiles + * @returns whether or not the app has already been granted user consent + */ + public synchronized boolean provisionVpnProfile( + @NonNull String packageName, @NonNull VpnProfile profile, @NonNull KeyStore keyStore) { + checkNotNull(packageName, "No package name provided"); + checkNotNull(profile, "No profile provided"); + checkNotNull(keyStore, "KeyStore missing"); + + verifyCallingUidAndPackage(packageName); + + final byte[] encodedProfile = profile.encode(); + if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) { + throw new IllegalArgumentException("Profile too big"); + } + + // Permissions checked during startVpnProfile() + Binder.withCleanCallingIdentity( + () -> { + keyStore.put( + getProfileNameForPackage(packageName), + encodedProfile, + Process.SYSTEM_UID, + 0 /* flags */); + }); + + // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop. + // This mirrors the prepareAndAuthorize that is used by VpnService. + + // Return whether the app is already pre-consented + return isVpnProfilePreConsented(mContext, packageName); + } + + /** + * Deletes an app-provisioned VPN profile. + * + * @param packageName the package name of the app provisioning this profile + * @param keyStore the System keystore instance to save VPN profiles + */ + public synchronized void deleteVpnProfile( + @NonNull String packageName, @NonNull KeyStore keyStore) { + checkNotNull(packageName, "No package name provided"); + checkNotNull(keyStore, "KeyStore missing"); + + verifyCallingUidAndPackage(packageName); + + Binder.withCleanCallingIdentity( + () -> { + keyStore.delete(getProfileNameForPackage(packageName), Process.SYSTEM_UID); + }); + } + + /** + * Retrieves the VpnProfile. + * + * <p>Must be used only as SYSTEM_UID, otherwise the key/UID pair will not match anything in the + * keystore. + */ + @VisibleForTesting + @Nullable + VpnProfile getVpnProfilePrivileged(@NonNull String packageName, @NonNull KeyStore keyStore) { + if (!mSystemServices.isCallerSystem()) { + Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID "); + return null; + } + + final byte[] encoded = keyStore.get(getProfileNameForPackage(packageName)); + if (encoded == null) return null; + + return VpnProfile.decode("" /* Key unused */, encoded); + } + + /** + * Starts an already provisioned VPN Profile, keyed by package name. + * + * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService). + * Privileged (system) callers should use startVpnProfilePrivileged instead. Otherwise the UIDs + * will not match during appop checks. + * + * @param packageName the package name of the app provisioning this profile + * @param keyStore the System keystore instance to retrieve VPN profiles + */ + public synchronized void startVpnProfile( + @NonNull String packageName, @NonNull KeyStore keyStore) { + checkNotNull(packageName, "No package name provided"); + checkNotNull(keyStore, "KeyStore missing"); + + // Prepare VPN for startup + if (!prepare(packageName, null /* newPackage */, true /* isPlatformVpn */)) { + throw new SecurityException("User consent not granted for package " + packageName); + } + + Binder.withCleanCallingIdentity( + () -> { + final VpnProfile profile = getVpnProfilePrivileged(packageName, keyStore); + if (profile == null) { + throw new IllegalArgumentException("No profile found for " + packageName); + } + + startVpnProfilePrivileged(profile); + }); + } + + private void startVpnProfilePrivileged(@NonNull VpnProfile profile) { + // TODO: Start PlatformVpnRunner + } + + /** + * Stops an already running VPN Profile for the given package. + * + * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService). + * Privileged (system) callers should (re-)prepare the LEGACY_VPN instead. + * + * @param packageName the package name of the app provisioning this profile + */ + public synchronized void stopVpnProfile(@NonNull String packageName) { + checkNotNull(packageName, "No package name provided"); + + // To stop the VPN profile, the caller must be the current prepared package. Otherwise, + // the app is not prepared, and we can just return. + if (!isCurrentPreparedPackage(packageName)) { + // TODO: Also check to make sure that the running VPN is a VPN profile. + return; + } + + prepareInternal(VpnConfig.LEGACY_VPN); + } } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 4ddc391bd889..6d130d91f639 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -212,8 +212,11 @@ public class SyncManager { private static final int SYNC_OP_STATE_VALID = 0; - private static final int SYNC_OP_STATE_INVALID = 1; + // "1" used to include errors 3, 4 and 5 but now it's split up. private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2; + private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT = 3; + private static final int SYNC_OP_STATE_INVALID_NOT_SYNCABLE = 4; + private static final int SYNC_OP_STATE_INVALID_SYNC_DISABLED = 5; /** Flags used when connecting to a sync adapter service */ private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE @@ -3206,12 +3209,10 @@ public class SyncManager { } final int syncOpState = computeSyncOpState(op); - switch (syncOpState) { - case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: - case SYNC_OP_STATE_INVALID: { - SyncJobService.callJobFinished(op.jobId, false, - "invalid op state: " + syncOpState); - } return; + if (syncOpState != SYNC_OP_STATE_VALID) { + SyncJobService.callJobFinished(op.jobId, false, + "invalid op state: " + syncOpState); + return; } if (!dispatchSyncOperation(op)) { @@ -3354,27 +3355,27 @@ public class SyncManager { pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE); final int syncOpState = computeSyncOpState(op); - switch (syncOpState) { - case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: { - String packageName = op.owningPackage; - final int userId = UserHandle.getUserId(op.owningUid); - // If the app did not run and has no account access, done - if (!wasPackageEverLaunched(packageName, userId)) { - return; - } - mAccountManagerInternal.requestAccountAccess(op.target.account, - packageName, userId, new RemoteCallback((Bundle result) -> { - if (result != null - && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { - updateOrAddPeriodicSync(target, pollFrequency, flex, extras); - } - } - )); - } return; - - case SYNC_OP_STATE_INVALID: { + if (syncOpState == SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS) { + String packageName = op.owningPackage; + final int userId = UserHandle.getUserId(op.owningUid); + // If the app did not run and has no account access, done + if (!wasPackageEverLaunched(packageName, userId)) { return; } + mLogger.log("requestAccountAccess for SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS"); + mAccountManagerInternal.requestAccountAccess(op.target.account, + packageName, userId, new RemoteCallback((Bundle result) -> { + if (result != null + && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { + updateOrAddPeriodicSync(target, pollFrequency, flex, extras); + } + } + )); + return; + } + if (syncOpState != SYNC_OP_STATE_VALID) { + mLogger.log("syncOpState=", syncOpState); + return; } scheduleSyncOperationH(op); @@ -3452,7 +3453,7 @@ public class SyncManager { Slog.v(TAG, " Dropping sync operation: account doesn't exist."); } Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist."); - return SYNC_OP_STATE_INVALID; + return SYNC_OP_STATE_INVALID_NO_ACCOUNT; } // Drop this sync request if it isn't syncable. state = computeSyncable(target.account, target.userId, target.provider, true); @@ -3469,7 +3470,7 @@ public class SyncManager { Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE"); } Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE"); - return SYNC_OP_STATE_INVALID; + return SYNC_OP_STATE_INVALID_NOT_SYNCABLE; } final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId) @@ -3488,7 +3489,7 @@ public class SyncManager { Slog.v(TAG, " Dropping sync operation: disallowed by settings/network."); } Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network"); - return SYNC_OP_STATE_INVALID; + return SYNC_OP_STATE_INVALID_SYNC_DISABLED; } return SYNC_OP_STATE_VALID; } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 7e8fe3ae8428..87a5730edc2e 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -91,8 +91,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { private void tryConnectDisplayLocked(long physicalDisplayId) { final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId); if (displayToken != null) { - SurfaceControl.PhysicalDisplayInfo[] configs = - SurfaceControl.getDisplayConfigs(displayToken); + SurfaceControl.DisplayInfo info = SurfaceControl.getDisplayInfo(displayToken); + if (info == null) { + Slog.w(TAG, "No valid info found for display device " + physicalDisplayId); + return; + } + SurfaceControl.DisplayConfig[] configs = SurfaceControl.getDisplayConfigs(displayToken); if (configs == null) { // There are no valid configs for this device, so we can't use it Slog.w(TAG, "No valid configs found for display device " + physicalDisplayId); @@ -115,19 +119,19 @@ final class LocalDisplayAdapter extends DisplayAdapter { activeColorMode = Display.COLOR_MODE_INVALID; } int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken); - SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs = + SurfaceControl.DesiredDisplayConfigSpecs configSpecs = SurfaceControl.getDesiredDisplayConfigSpecs(displayToken); LocalDisplayDevice device = mDevices.get(physicalDisplayId); if (device == null) { // Display was added. final boolean isInternal = mDevices.size() == 0; - device = new LocalDisplayDevice(displayToken, physicalDisplayId, configs, - activeConfig, desiredDisplayConfigSpecs, colorModes, activeColorMode, + device = new LocalDisplayDevice(displayToken, physicalDisplayId, info, + configs, activeConfig, configSpecs, colorModes, activeColorMode, isInternal); mDevices.put(physicalDisplayId, device); sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); - } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig, - desiredDisplayConfigSpecs, colorModes, activeColorMode)) { + } else if (device.updateDisplayConfigsLocked(configs, activeConfig, configSpecs, + colorModes, activeColorMode)) { // Display properties changed. sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); } @@ -179,7 +183,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs = new DisplayModeDirector.DesiredDisplayModeSpecs(); private boolean mDisplayModeSpecsInvalid; - private int mActivePhysIndex; + private int mActiveConfigId; private int mActiveColorMode; private boolean mActiveColorModeInvalid; private Display.HdrCapabilities mHdrCapabilities; @@ -189,21 +193,25 @@ final class LocalDisplayAdapter extends DisplayAdapter { private boolean mGameContentTypeRequested; private boolean mSidekickActive; private SidekickInternal mSidekickInternal; - private SurfaceControl.PhysicalDisplayInfo[] mDisplayInfos; + private SurfaceControl.DisplayInfo mDisplayInfo; + private SurfaceControl.DisplayConfig[] mDisplayConfigs; private Spline mSystemBrightnessToNits; private Spline mNitsToHalBrightness; private boolean mHalBrightnessSupport; LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, - SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo, - SurfaceControl.DesiredDisplayConfigSpecs physicalDisplayConfigSpecs, + SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs, + int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs, int[] colorModes, int activeColorMode, boolean isInternal) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId); mPhysicalDisplayId = physicalDisplayId; mIsInternal = isInternal; - updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo, - physicalDisplayConfigSpecs, colorModes, activeColorMode); + mDisplayInfo = info; + + updateDisplayConfigsLocked(configs, activeConfigId, configSpecs, colorModes, + activeColorMode); updateColorModesLocked(colorModes, activeColorMode); + mSidekickInternal = LocalServices.getService(SidekickInternal.class); if (mIsInternal) { LightsManager lights = LocalServices.getService(LightsManager.class); @@ -226,23 +234,24 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } - public boolean updatePhysicalDisplayInfoLocked( - SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo, - SurfaceControl.DesiredDisplayConfigSpecs physicalDisplayConfigSpecs, - int[] colorModes, int activeColorMode) { - mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length); - mActivePhysIndex = activeDisplayInfo; + public boolean updateDisplayConfigsLocked( + SurfaceControl.DisplayConfig[] configs, int activeConfigId, + SurfaceControl.DesiredDisplayConfigSpecs configSpecs, int[] colorModes, + int activeColorMode) { + mDisplayConfigs = Arrays.copyOf(configs, configs.length); + mActiveConfigId = activeConfigId; + // Build an updated list of all existing modes. ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>(); boolean modesAdded = false; - for (int i = 0; i < physicalDisplayInfos.length; i++) { - SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i]; + for (int i = 0; i < configs.length; i++) { + SurfaceControl.DisplayConfig config = configs[i]; // First, check to see if we've already added a matching mode. Since not all // configuration options are exposed via Display.Mode, it's possible that we have - // multiple PhysicalDisplayInfos that would generate the same Display.Mode. + // multiple DisplayConfigs that would generate the same Display.Mode. boolean existingMode = false; for (int j = 0; j < records.size(); j++) { - if (records.get(j).hasMatchingMode(info)) { + if (records.get(j).hasMatchingMode(config)) { existingMode = true; break; } @@ -253,9 +262,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { // If we haven't already added a mode for this configuration to the new set of // supported modes then check to see if we have one in the prior set of supported // modes to reuse. - DisplayModeRecord record = findDisplayModeRecord(info); + DisplayModeRecord record = findDisplayModeRecord(config); if (record == null) { - record = new DisplayModeRecord(info); + record = new DisplayModeRecord(config); modesAdded = true; } records.add(record); @@ -265,7 +274,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { DisplayModeRecord activeRecord = null; for (int i = 0; i < records.size(); i++) { DisplayModeRecord record = records.get(i); - if (record.hasMatchingMode(physicalDisplayInfos[activeDisplayInfo])){ + if (record.hasMatchingMode(configs[activeConfigId])) { activeRecord = record; break; } @@ -282,17 +291,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { // Check whether surface flinger spontaneously changed display config specs out from // under us. If so, schedule a traversal to reapply our display config specs. if (mDisplayModeSpecs.baseModeId != 0) { - int activeBaseMode = - findMatchingModeIdLocked(physicalDisplayConfigSpecs.defaultConfig); + int activeBaseMode = findMatchingModeIdLocked(configSpecs.defaultConfig); // If we can't map the defaultConfig index to a mode, then the physical display // configs must have changed, and the code below for handling changes to the // list of available modes will take care of updating display config specs. if (activeBaseMode != 0) { if (mDisplayModeSpecs.baseModeId != activeBaseMode - || mDisplayModeSpecs.refreshRateRange.min - != physicalDisplayConfigSpecs.minRefreshRate + || mDisplayModeSpecs.refreshRateRange.min != configSpecs.minRefreshRate || mDisplayModeSpecs.refreshRateRange.max - != physicalDisplayConfigSpecs.maxRefreshRate) { + != configSpecs.maxRefreshRate) { mDisplayModeSpecsInvalid = true; sendTraversalRequestLocked(); } @@ -313,7 +320,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { } // Update the default mode, if needed. - if (findDisplayInfoIndexLocked(mDefaultModeId) < 0) { + if (findDisplayConfigIdLocked(mDefaultModeId) < 0) { if (mDefaultModeId != 0) { Slog.w(TAG, "Default display mode no longer available, using currently" + " active mode as default."); @@ -434,10 +441,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } - private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) { + private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config) { for (int i = 0; i < mSupportedModes.size(); i++) { DisplayModeRecord record = mSupportedModes.valueAt(i); - if (record.hasMatchingMode(info)) { + if (record.hasMatchingMode(config)) { return record; } } @@ -455,10 +462,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { @Override public DisplayDeviceInfo getDisplayDeviceInfoLocked() { if (mInfo == null) { - SurfaceControl.PhysicalDisplayInfo phys = mDisplayInfos[mActivePhysIndex]; + SurfaceControl.DisplayConfig config = mDisplayConfigs[mActiveConfigId]; mInfo = new DisplayDeviceInfo(); - mInfo.width = phys.width; - mInfo.height = phys.height; + mInfo.width = config.width; + mInfo.height = config.height; mInfo.modeId = mActiveModeId; mInfo.defaultModeId = mDefaultModeId; mInfo.supportedModes = getDisplayModes(mSupportedModes); @@ -471,20 +478,20 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.supportedColorModes[i] = mSupportedColorModes.get(i); } mInfo.hdrCapabilities = mHdrCapabilities; - mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos; - mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos; + mInfo.appVsyncOffsetNanos = config.appVsyncOffsetNanos; + mInfo.presentationDeadlineNanos = config.presentationDeadlineNanos; mInfo.state = mState; mInfo.uniqueId = getUniqueId(); final DisplayAddress.Physical physicalAddress = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); mInfo.address = physicalAddress; - mInfo.densityDpi = (int) (phys.density * 160 + 0.5f); - mInfo.xDpi = phys.xDpi; - mInfo.yDpi = phys.yDpi; + mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f); + mInfo.xDpi = config.xDpi; + mInfo.yDpi = config.yDpi; // Assume that all built-in displays that have secure output (eg. HDCP) also // support compositing from gralloc protected buffers. - if (phys.secure) { + if (mDisplayInfo.secure) { mInfo.flags = DisplayDeviceInfo.FLAG_SECURE | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; } @@ -721,8 +728,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { // a valid mode. return; } - int basePhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.baseModeId); - if (basePhysIndex < 0) { + int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId); + if (baseConfigId < 0) { // When a display is hotplugged, it's possible for a mode to be removed that was // previously valid. Because of the way display changes are propagated through the // framework, and the caching of the display mode specs in LogicalDisplay, it's @@ -740,7 +747,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { getHandler().sendMessage(PooledLambda.obtainMessage( LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this, getDisplayTokenLocked(), - new SurfaceControl.DesiredDisplayConfigSpecs(basePhysIndex, + new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId, mDisplayModeSpecs.refreshRateRange.min, mDisplayModeSpecs.refreshRateRange.max))); } @@ -764,22 +771,22 @@ final class LocalDisplayAdapter extends DisplayAdapter { updateDeviceInfoLocked(); } - public void onActivePhysicalDisplayModeChangedLocked(int physIndex) { - if (updateActiveModeLocked(physIndex)) { + public void onActiveDisplayConfigChangedLocked(int configId) { + if (updateActiveModeLocked(configId)) { updateDeviceInfoLocked(); } } - public boolean updateActiveModeLocked(int activePhysIndex) { - if (mActivePhysIndex == activePhysIndex) { + public boolean updateActiveModeLocked(int activeConfigId) { + if (mActiveConfigId == activeConfigId) { return false; } - mActivePhysIndex = activePhysIndex; - mActiveModeId = findMatchingModeIdLocked(activePhysIndex); + mActiveConfigId = activeConfigId; + mActiveModeId = findMatchingModeIdLocked(activeConfigId); mActiveModeInvalid = mActiveModeId == 0; if (mActiveModeInvalid) { Slog.w(TAG, "In unknown mode after setting allowed configs" - + ", activePhysIndex=" + mActivePhysIndex); + + ", activeConfigId=" + mActiveConfigId); } return true; } @@ -850,7 +857,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId); pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}"); pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid); - pw.println("mActivePhysIndex=" + mActivePhysIndex); + pw.println("mActiveConfigId=" + mActiveConfigId); pw.println("mActiveModeId=" + mActiveModeId); pw.println("mActiveColorMode=" + mActiveColorMode); pw.println("mDefaultModeId=" + mDefaultModeId); @@ -861,9 +868,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mAllmRequested=" + mAllmRequested); pw.println("mGameContentTypeSupported" + mGameContentTypeSupported); pw.println("mGameContentTypeRequested" + mGameContentTypeRequested); - pw.println("mDisplayInfos="); - for (int i = 0; i < mDisplayInfos.length; i++) { - pw.println(" " + mDisplayInfos[i]); + pw.println("mDisplayInfo=" + mDisplayInfo); + pw.println("mDisplayConfigs="); + for (int i = 0; i < mDisplayConfigs.length; i++) { + pw.println(" " + mDisplayConfigs[i]); } pw.println("mSupportedModes="); for (int i = 0; i < mSupportedModes.size(); i++) { @@ -879,12 +887,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("]"); } - private int findDisplayInfoIndexLocked(int modeId) { + private int findDisplayConfigIdLocked(int modeId) { DisplayModeRecord record = mSupportedModes.get(modeId); if (record != null) { - for (int i = 0; i < mDisplayInfos.length; i++) { - SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[i]; - if (record.hasMatchingMode(info)){ + for (int i = 0; i < mDisplayConfigs.length; i++) { + SurfaceControl.DisplayConfig config = mDisplayConfigs[i]; + if (record.hasMatchingMode(config)) { return i; } } @@ -892,11 +900,11 @@ final class LocalDisplayAdapter extends DisplayAdapter { return -1; } - private int findMatchingModeIdLocked(int physIndex) { - SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[physIndex]; + private int findMatchingModeIdLocked(int configId) { + SurfaceControl.DisplayConfig config = mDisplayConfigs[configId]; for (int i = 0; i < mSupportedModes.size(); i++) { DisplayModeRecord record = mSupportedModes.valueAt(i); - if (record.hasMatchingMode(info)) { + if (record.hasMatchingMode(config)) { return record.mMode.getModeId(); } } @@ -948,23 +956,23 @@ final class LocalDisplayAdapter extends DisplayAdapter { private static final class DisplayModeRecord { public final Display.Mode mMode; - public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys) { - mMode = createMode(phys.width, phys.height, phys.refreshRate); + DisplayModeRecord(SurfaceControl.DisplayConfig config) { + mMode = createMode(config.width, config.height, config.refreshRate); } /** - * Returns whether the mode generated by the given PhysicalDisplayInfo matches the mode + * Returns whether the mode generated by the given DisplayConfig matches the mode * contained by the record modulo mode ID. * - * Note that this doesn't necessarily mean the the PhysicalDisplayInfos are identical, just + * Note that this doesn't necessarily mean that the DisplayConfigs are identical, just * that they generate identical modes. */ - public boolean hasMatchingMode(SurfaceControl.PhysicalDisplayInfo info) { + public boolean hasMatchingMode(SurfaceControl.DisplayConfig config) { int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate()); - int displayInfoRefreshRate = Float.floatToIntBits(info.refreshRate); - return mMode.getPhysicalWidth() == info.width - && mMode.getPhysicalHeight() == info.height - && modeRefreshRate == displayInfoRefreshRate; + int configRefreshRate = Float.floatToIntBits(config.refreshRate); + return mMode.getPhysicalWidth() == config.width + && mMode.getPhysicalHeight() == config.height + && modeRefreshRate == configRefreshRate; } public String toString() { @@ -989,12 +997,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void onConfigChanged(long timestampNanos, long physicalDisplayId, int physIndex) { + public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { if (DEBUG) { Slog.d(TAG, "onConfigChanged(" + "timestampNanos=" + timestampNanos + ", physicalDisplayId=" + physicalDisplayId - + ", physIndex=" + physIndex + ")"); + + ", configId=" + configId + ")"); } synchronized (getSyncRoot()) { LocalDisplayDevice device = mDevices.get(physicalDisplayId); @@ -1005,7 +1013,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { } return; } - device.onActivePhysicalDisplayModeChangedLocked(physIndex); + device.onActiveDisplayConfigChangedLocked(configId); } } } diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 15dd6464e094..9754b6d4db02 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -46,11 +46,12 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; +import android.provider.Settings; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.integrity.engine.RuleEvaluationEngine; import com.android.server.integrity.model.IntegrityCheckResult; @@ -67,6 +68,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -105,6 +107,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private final RuleEvaluationEngine mEvaluationEngine; private final IntegrityFileManager mIntegrityFileManager; + private final boolean mCheckIntegrityForRuleProviders; + /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */ public static AppIntegrityManagerServiceImpl create(Context context) { HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler"); @@ -115,7 +119,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { LocalServices.getService(PackageManagerInternal.class), RuleEvaluationEngine.getRuleEvaluationEngine(), IntegrityFileManager.getInstance(), - handlerThread.getThreadHandler()); + handlerThread.getThreadHandler(), + Settings.Global.getInt( + context.getContentResolver(), + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, + 0) + == 1 + ); } @VisibleForTesting @@ -124,12 +134,14 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { PackageManagerInternal packageManagerInternal, RuleEvaluationEngine evaluationEngine, IntegrityFileManager integrityFileManager, - Handler handler) { + Handler handler, + boolean checkIntegrityForRuleProviders) { mContext = context; mPackageManagerInternal = packageManagerInternal; mEvaluationEngine = evaluationEngine; mIntegrityFileManager = integrityFileManager; mHandler = handler; + mCheckIntegrityForRuleProviders = checkIntegrityForRuleProviders; IntentFilter integrityVerificationFilter = new IntentFilter(); integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); @@ -170,7 +182,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { success = false; } - StatsLog.write(StatsLog.INTEGRITY_RULES_PUSHED, success, ruleProvider, version); + FrameworkStatsLog.write(FrameworkStatsLog.INTEGRITY_RULES_PUSHED, success, + ruleProvider, version); Intent intent = new Intent(); intent.putExtra(EXTRA_STATUS, success ? STATUS_SUCCESS : STATUS_FAILURE); @@ -207,6 +220,17 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { : ""; } + @Override + public ParceledListSlice<Rule> getCurrentRules() { + List<Rule> rules = Collections.emptyList(); + try { + rules = mIntegrityFileManager.readRules(/* appInstallMetadata= */ null); + } catch (Exception e) { + Slog.e(TAG, "Error getting current rules", e); + } + return new ParceledListSlice<>(rules); + } + private void handleIntegrityVerification(Intent intent) { int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); @@ -228,7 +252,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { String installerPackageName = getInstallerPackageName(intent); // Skip integrity verification if the verifier is doing the install. - if (isRuleProvider(installerPackageName)) { + if (!mCheckIntegrityForRuleProviders + && isRuleProvider(installerPackageName)) { Slog.i(TAG, "Verifier doing the install. Skipping integrity check."); mPackageManagerInternal.setIntegrityVerificationResult( verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); @@ -262,8 +287,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { + " due to " + result.getMatchedRules()); - StatsLog.write( - StatsLog.INTEGRITY_CHECK_RESULT_REPORTED, + FrameworkStatsLog.write( + FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED, packageName, appCert, appInstallMetadata.getVersionCode(), @@ -295,7 +320,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { * Verify the UID and return the installer package name. * * @return the package name of the installer, or null if it cannot be determined or it is - * installed via adb. + * installed via adb. */ @Nullable private String getInstallerPackageName(Intent intent) { @@ -584,12 +609,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } private List<String> getAllowedRuleProviders() { - return Arrays.asList(mContext.getResources().getStringArray( - R.array.config_integrityRuleProviderPackages)); + return Arrays.asList( + mContext.getResources() + .getStringArray(R.array.config_integrityRuleProviderPackages)); } private boolean isRuleProvider(String installerPackageName) { - return getAllowedRuleProviders().stream().anyMatch( - ruleProvider -> ruleProvider.equals(installerPackageName)); + return getAllowedRuleProviders().stream() + .anyMatch(ruleProvider -> ruleProvider.equals(installerPackageName)); } } diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java index fffe7d9030ff..7f0231e72373 100644 --- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java +++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java @@ -147,19 +147,21 @@ public class IntegrityFileManager { /** * Read rules from persistent storage. * - * @param appInstallMetadata information about the install used to select rules to read + * @param appInstallMetadata information about the install used to select rules to read. If + * null, all rules will be read. */ - public List<Rule> readRules(AppInstallMetadata appInstallMetadata) + public List<Rule> readRules(@Nullable AppInstallMetadata appInstallMetadata) throws IOException, RuleParseException { synchronized (RULES_LOCK) { // Try to identify indexes from the index file. - List<RuleIndexRange> ruleReadingIndexes; - try { - ruleReadingIndexes = - mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata); - } catch (Exception e) { - Slog.w(TAG, "Error identifying the rule indexes. Trying unindexed.", e); - ruleReadingIndexes = Collections.emptyList(); + List<RuleIndexRange> ruleReadingIndexes = Collections.emptyList(); + if (appInstallMetadata != null) { + try { + ruleReadingIndexes = + mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata); + } catch (Exception e) { + Slog.w(TAG, "Error identifying the rule indexes. Trying unindexed.", e); + } } // Read the rules based on the index information when available. diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java index 1b605c7c430c..1fa067065e1b 100644 --- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java +++ b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java @@ -18,7 +18,8 @@ package com.android.server.integrity.model; import android.annotation.Nullable; import android.content.integrity.Rule; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import java.util.Collections; import java.util.List; @@ -86,11 +87,11 @@ public final class IntegrityCheckResult { */ public int getLoggingResponse() { if (getEffect() == Effect.DENY) { - return StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED; + return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED; } else if (getEffect() == Effect.ALLOW && getMatchedRules().isEmpty()) { - return StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED; + return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED; } else if (getEffect() == Effect.ALLOW && !getMatchedRules().isEmpty()) { - return StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED; + return FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED; } else { throw new IllegalStateException("IntegrityCheckResult is not valid."); } diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index d01499668e8c..00e054596cd7 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -87,7 +87,7 @@ public class RuleBinarySerializer implements RuleSerializer { } if (rules.size() > TOTAL_RULE_SIZE_LIMIT) { - throw new IllegalArgumentException("Too many rules provided."); + throw new IllegalArgumentException("Too many rules provided: " + rules.size()); } // Determine the indexing groups and the order of the rules within each indexed group. @@ -134,7 +134,11 @@ public class RuleBinarySerializer implements RuleSerializer { .map(list -> list.size()) .collect(Collectors.summingInt(Integer::intValue)); if (totalRuleCount > ruleSizeLimit) { - throw new IllegalArgumentException("Too many rules provided in the indexing group."); + throw new IllegalArgumentException( + "Too many rules provided in the indexing group. Provided " + + totalRuleCount + + " limit " + + ruleSizeLimit); } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index baae4ea502d5..1f4048f821e5 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -139,6 +139,7 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; +import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyStoreException; @@ -224,6 +225,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final KeyStore mKeyStore; private final RecoverableKeyStoreManager mRecoverableKeyStoreManager; + private ManagedProfilePasswordCache mManagedProfilePasswordCache; private final RebootEscrowManager mRebootEscrowManager; @@ -387,6 +389,7 @@ public class LockSettingsService extends ILockSettings.Stub { setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId, /* isLockTiedToParent= */ true); tieProfileLockToParent(managedUserId, unifiedProfilePassword); + mManagedProfilePasswordCache.storePassword(managedUserId, unifiedProfilePassword); } } @@ -527,6 +530,16 @@ public class LockSettingsService extends ILockSettings.Stub { int defaultValue) { return Settings.Global.getInt(contentResolver, keyName, defaultValue); } + + public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() { + try { + java.security.KeyStore ks = java.security.KeyStore.getInstance("AndroidKeyStore"); + ks.load(null); + return new ManagedProfilePasswordCache(ks, getUserManager()); + } catch (Exception e) { + throw new IllegalStateException("Cannot load keystore", e); + } + } } public LockSettingsService(Context context) { @@ -560,6 +573,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStrongAuthTracker.register(mStrongAuth); mSpManager = injector.getSyntheticPasswordManager(mStorage); + mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(); mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(), mStorage); @@ -706,7 +720,8 @@ public class LockSettingsService extends ILockSettings.Stub { private void ensureProfileKeystoreUnlocked(int userId) { final KeyStore ks = KeyStore.getInstance(); if (ks.state(userId) == KeyStore.State.LOCKED - && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) { + && mUserManager.getUserInfo(userId).isManagedProfile() + && hasUnifiedChallenge(userId)) { Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore"); // If boot took too long and the password in vold got expired, parent keystore will // be still locked, we ignore this case since the user will be prompted to unlock @@ -1302,6 +1317,7 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential credential = LockscreenCredential.createManagedPassword( decryptionResult); Arrays.fill(decryptionResult, (byte) 0); + mManagedProfilePasswordCache.storePassword(userId, credential); return credential; } @@ -1381,12 +1397,25 @@ public class LockSettingsService extends ILockSettings.Stub { } for (UserInfo profile : mUserManager.getProfiles(userId)) { - // Unlock managed profile with unified lock - if (tiedManagedProfileReadyToUnlock(profile)) { - // Must pass the challenge on for resetLockout, so it's not over-written, which - // causes LockSettingsService to revokeChallenge inappropriately. - unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, - challengeType, challenge, resetLockouts); + if (profile.id == userId) continue; + if (!profile.isManagedProfile()) continue; + + if (hasUnifiedChallenge(profile.id)) { + if (mUserManager.isUserRunning(profile.id)) { + // Unlock managed profile with unified lock + // Must pass the challenge on for resetLockout, so it's not over-written, which + // causes LockSettingsService to revokeChallenge inappropriately. + unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, + challengeType, challenge, resetLockouts); + } else { + try { + // Profile not ready for unlock yet, but decrypt the unified challenge now + // so it goes into the cache + getDecryptedPasswordForTiedProfile(profile.id); + } catch (GeneralSecurityException | IOException e) { + Slog.d(TAG, "Cache work profile password failed", e); + } + } } // Now we have unlocked the parent user and attempted to unlock the profile we should // show notifications if the profile is still locked. @@ -1417,11 +1446,9 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) { - return userInfo.isManagedProfile() - && !getSeparateProfileChallengeEnabledInternal(userInfo.id) - && mStorage.hasChildProfileLock(userInfo.id) - && mUserManager.isUserRunning(userInfo.id); + private boolean hasUnifiedChallenge(int userId) { + return !getSeparateProfileChallengeEnabledInternal(userId) + && mStorage.hasChildProfileLock(userId); } private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) { @@ -2233,6 +2260,7 @@ public class LockSettingsService extends ILockSettings.Stub { final KeyStore ks = KeyStore.getInstance(); ks.onUserRemoved(userId); + mManagedProfilePasswordCache.removePassword(userId); gateKeeperClearSecureUserId(userId); if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) { @@ -2783,6 +2811,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); setUserPasswordMetrics(credential, userId); + mManagedProfilePasswordCache.removePassword(userId); if (profilePasswords != null) { for (Map.Entry<Integer, LockscreenCredential> entry : profilePasswords.entrySet()) { @@ -3097,6 +3126,22 @@ public class LockSettingsService extends ILockSettings.Stub { return true; } + @Override + public boolean tryUnlockWithCachedUnifiedChallenge(int userId) { + try (LockscreenCredential cred = mManagedProfilePasswordCache.retrievePassword(userId)) { + if (cred == null) { + return false; + } + return doVerifyCredential(cred, CHALLENGE_NONE, 0, userId, null /* progressCallback */) + .getResponseCode() == VerifyCredentialResponse.RESPONSE_OK; + } + } + + @Override + public void removeCachedUnifiedChallenge(int userId) { + mManagedProfilePasswordCache.removePassword(userId); + } + static String timestampToString(long timestamp) { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp)); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 4943c25b1f18..7b767b86f0d4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -44,6 +44,7 @@ class LockSettingsShellCommand extends ShellCommand { private static final String COMMAND_SET_DISABLED = "set-disabled"; private static final String COMMAND_VERIFY = "verify"; private static final String COMMAND_GET_DISABLED = "get-disabled"; + private static final String COMMAND_REMOVE_CACHE = "remove-cache"; private static final String COMMAND_HELP = "help"; private int mCurrentUserId; @@ -76,6 +77,15 @@ class LockSettingsShellCommand extends ShellCommand { return -1; } } + switch (cmd) { + // Commands that do not require authentication go here. + case COMMAND_REMOVE_CACHE: + runRemoveCache(); + return 0; + case COMMAND_HELP: + onHelp(); + return 0; + } if (!checkCredential()) { return -1; } @@ -105,9 +115,6 @@ class LockSettingsShellCommand extends ShellCommand { case COMMAND_GET_DISABLED: runGetDisabled(); break; - case COMMAND_HELP: - onHelp(); - break; default: getErrPrintWriter().println("Unknown command: " + cmd); break; @@ -163,6 +170,9 @@ class LockSettingsShellCommand extends ShellCommand { pw.println(" verify [--old <CREDENTIAL>] [--user USER_ID]"); pw.println(" Verifies the lock credentials."); pw.println(""); + pw.println(" remove-cache [--user USER_ID]"); + pw.println(" Removes cached unified challenge for the managed profile."); + pw.println(""); } } @@ -322,4 +332,9 @@ class LockSettingsShellCommand extends ShellCommand { return true; } } + + private void runRemoveCache() { + mLockPatternUtils.removeCachedUnifiedChallenge(mCurrentUserId); + getOutPrintWriter().println("Password cached removed for user " + mCurrentUserId); + } } diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java new file mode 100644 index 000000000000..d38ee678c7aa --- /dev/null +++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java @@ -0,0 +1,191 @@ +/* + * 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.server.locksettings; + +import android.annotation.Nullable; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; +import android.security.keystore.AndroidKeyStoreSpi; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.security.keystore.UserNotAuthenticatedException; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.widget.LockscreenCredential; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; + +/** + * Caches *unified* work challenge for user 0's managed profiles. Only user 0's profile is supported + * at the moment because the cached credential is encrypted using a keystore key auth-bound to + * user 0: this is to match how unified work challenge is similarly auth-bound to its parent user's + * lockscreen credential normally. It's possible to extend this class to support managed profiles + * for secondary users, that will require generating auth-bound keys to their corresponding parent + * user though (which {@link KeyGenParameterSpec} does not support right now). + * + * <p> The cache is filled whenever the managed profile's unified challenge is created or derived + * (as part of the parent user's credential verification flow). It's removed when the profile is + * deleted or a (separate) lockscreen credential is explicitly set on the profile. There is also + * an ADB command to evict the cache "cmd lock_settings remove-cache --user X", to assist + * development and testing. + + * <p> The encrypted credential is stored in-memory only so the cache does not persist across + * reboots. + */ +public class ManagedProfilePasswordCache { + + private static final String TAG = "ManagedProfilePasswordCache"; + private static final int KEY_LENGTH = 256; + private static final int CACHE_TIMEOUT_SECONDS = (int) TimeUnit.DAYS.toSeconds(7); + + private final SparseArray<byte[]> mEncryptedPasswords = new SparseArray<>(); + private final KeyStore mKeyStore; + private final UserManager mUserManager; + + public ManagedProfilePasswordCache(KeyStore keyStore, UserManager userManager) { + mKeyStore = keyStore; + mUserManager = userManager; + } + + /** + * Encrypt and store the password in the cache. Does NOT overwrite existing password cache + * if one for the given user already exists. + */ + public void storePassword(int userId, LockscreenCredential password) { + synchronized (mEncryptedPasswords) { + if (mEncryptedPasswords.contains(userId)) { + return; + } + UserInfo parent = mUserManager.getProfileParent(userId); + if (parent == null || parent.id != UserHandle.USER_SYSTEM) { + // Since the cached password is encrypted using a keystore key auth-bound to user 0, + // only support caching password for user 0's profile. + return; + } + String keyName = getEncryptionKeyName(userId); + KeyGenerator generator; + SecretKey key; + try { + generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, + AndroidKeyStoreSpi.NAME); + generator.init(new KeyGenParameterSpec.Builder( + keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setKeySize(KEY_LENGTH) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + // Generate auth-bound key to user 0 (since we the caller is user 0) + .setUserAuthenticationRequired(true) + .setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS) + // Only accessible after user 0's keyguard is unlocked + .setUnlockedDeviceRequired(true) + .build()); + key = generator.generateKey(); + } catch (GeneralSecurityException e) { + Slog.e(TAG, "Cannot generate key", e); + return; + } + + Cipher cipher; + try { + cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] ciphertext = cipher.doFinal(password.getCredential()); + byte[] iv = cipher.getIV(); + byte[] block = Arrays.copyOf(iv, ciphertext.length + iv.length); + System.arraycopy(ciphertext, 0, block, iv.length, ciphertext.length); + mEncryptedPasswords.put(userId, block); + } catch (GeneralSecurityException e) { + Slog.d(TAG, "Cannot encrypt", e); + } + } + } + + /** Attempt to retrieve the password for the given user. Returns {@code null} if it's not in the + * cache or if decryption fails. + */ + public @Nullable LockscreenCredential retrievePassword(int userId) { + synchronized (mEncryptedPasswords) { + byte[] block = mEncryptedPasswords.get(userId); + if (block == null) { + return null; + } + Key key; + try { + key = mKeyStore.getKey(getEncryptionKeyName(userId), null); + } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { + Slog.d(TAG, "Cannot get key", e); + return null; + } + if (key == null) { + return null; + } + byte[] iv = Arrays.copyOf(block, 12); + byte[] ciphertext = Arrays.copyOfRange(block, 12, block.length); + byte[] credential; + try { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv)); + credential = cipher.doFinal(ciphertext); + } catch (UserNotAuthenticatedException e) { + Slog.i(TAG, "Device not unlocked for more than 7 days"); + return null; + } catch (GeneralSecurityException e) { + Slog.d(TAG, "Cannot decrypt", e); + return null; + } + LockscreenCredential result = LockscreenCredential.createManagedPassword(credential); + Arrays.fill(credential, (byte) 0); + return result; + } + } + + /** Remove the given user's password from cache, if one exists. */ + public void removePassword(int userId) { + synchronized (mEncryptedPasswords) { + String keyName = getEncryptionKeyName(userId); + try { + if (mKeyStore.containsAlias(keyName)) { + mKeyStore.deleteEntry(keyName); + } + } catch (KeyStoreException e) { + Slog.d(TAG, "Cannot delete key", e); + } + if (mEncryptedPasswords.contains(userId)) { + Arrays.fill(mEncryptedPasswords.get(userId), (byte) 0); + mEncryptedPasswords.remove(userId); + } + } + } + + private static String getEncryptionKeyName(int userId) { + return "com.android.server.locksettings.unified_profile_cache_" + userId; + } +} diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowData.java b/services/core/java/com/android/server/locksettings/RebootEscrowData.java index aee608e8a544..2b1907985aeb 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowData.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowData.java @@ -26,16 +26,12 @@ import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; /** * Holds the data necessary to complete a reboot escrow of the Synthetic Password. @@ -47,17 +43,11 @@ class RebootEscrowData { */ private static final int CURRENT_VERSION = 1; - /** The secret key will be of this format. */ - private static final String KEY_ALGO = "AES"; - - /** The key size used for encrypting the reboot escrow data. */ - private static final int KEY_SIZE_BITS = 256; - /** The algorithm used for the encryption of the key blob. */ private static final String CIPHER_ALGO = "AES/GCM/NoPadding"; private RebootEscrowData(byte spVersion, byte[] iv, byte[] syntheticPassword, byte[] blob, - byte[] key) { + RebootEscrowKey key) { mSpVersion = spVersion; mIv = iv; mSyntheticPassword = syntheticPassword; @@ -69,7 +59,7 @@ class RebootEscrowData { private final byte[] mIv; private final byte[] mSyntheticPassword; private final byte[] mBlob; - private final byte[] mKey; + private final RebootEscrowKey mKey; public byte getSpVersion() { return mSpVersion; @@ -87,17 +77,13 @@ class RebootEscrowData { return mBlob; } - public byte[] getKey() { + public RebootEscrowKey getKey() { return mKey; } - static SecretKeySpec fromKeyBytes(byte[] keyBytes) { - return new SecretKeySpec(keyBytes, KEY_ALGO); - } - - static RebootEscrowData fromEncryptedData(SecretKeySpec keySpec, byte[] blob) + static RebootEscrowData fromEncryptedData(RebootEscrowKey key, byte[] blob) throws IOException { - Preconditions.checkNotNull(keySpec); + Preconditions.checkNotNull(key); Preconditions.checkNotNull(blob); DataInputStream dis = new DataInputStream(new ByteArrayInputStream(blob)); @@ -126,7 +112,7 @@ class RebootEscrowData { final byte[] syntheticPassword; try { Cipher c = Cipher.getInstance(CIPHER_ALGO); - c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv)); + c.init(Cipher.DECRYPT_MODE, key.getKey(), new IvParameterSpec(iv)); syntheticPassword = c.doFinal(cipherText); } catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException @@ -134,30 +120,22 @@ class RebootEscrowData { throw new IOException("Could not decrypt ciphertext", e); } - return new RebootEscrowData(spVersion, iv, syntheticPassword, blob, keySpec.getEncoded()); + return new RebootEscrowData(spVersion, iv, syntheticPassword, blob, key); } - static RebootEscrowData fromSyntheticPassword(byte spVersion, byte[] syntheticPassword) + static RebootEscrowData fromSyntheticPassword(RebootEscrowKey key, byte spVersion, + byte[] syntheticPassword) throws IOException { Preconditions.checkNotNull(syntheticPassword); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); - final SecretKey secretKey; - try { - KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGO); - keyGenerator.init(KEY_SIZE_BITS, new SecureRandom()); - secretKey = keyGenerator.generateKey(); - } catch (NoSuchAlgorithmException e) { - throw new IOException("Could not generate new secret key", e); - } - final byte[] cipherText; final byte[] iv; try { Cipher cipher = Cipher.getInstance(CIPHER_ALGO); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); + cipher.init(Cipher.ENCRYPT_MODE, key.getKey()); cipherText = cipher.doFinal(syntheticPassword); iv = cipher.getIV(); } catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException @@ -173,6 +151,6 @@ class RebootEscrowData { dos.write(cipherText); return new RebootEscrowData(spVersion, iv, syntheticPassword, bos.toByteArray(), - secretKey.getEncoded()); + key); } } diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowKey.java b/services/core/java/com/android/server/locksettings/RebootEscrowKey.java new file mode 100644 index 000000000000..5367319caa85 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/RebootEscrowKey.java @@ -0,0 +1,67 @@ +/* + * 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.server.locksettings; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +/** + * Key used to encrypt and decrypt the {@link RebootEscrowData}. + */ +class RebootEscrowKey { + + /** The secret key will be of this format. */ + private static final String KEY_ALGO = "AES"; + + /** The key size used for encrypting the reboot escrow data. */ + private static final int KEY_SIZE_BITS = 256; + + private final SecretKey mKey; + + private RebootEscrowKey(SecretKey key) { + mKey = key; + } + + static RebootEscrowKey fromKeyBytes(byte[] keyBytes) { + return new RebootEscrowKey(new SecretKeySpec(keyBytes, KEY_ALGO)); + } + + static RebootEscrowKey generate() throws IOException { + final SecretKey secretKey; + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGO); + keyGenerator.init(KEY_SIZE_BITS, new SecureRandom()); + secretKey = keyGenerator.generateKey(); + } catch (NoSuchAlgorithmException e) { + throw new IOException("Could not generate new secret key", e); + } + return new RebootEscrowKey(secretKey); + } + + SecretKey getKey() { + return mKey; + } + + byte[] getKeyBytes() { + return mKey.getEncoded(); + } +} diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 46ea9d11d1dc..e991f96b208f 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -25,27 +25,26 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserManager; import android.util.Slog; -import android.util.StatsLog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.RebootEscrowListener; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.crypto.spec.SecretKeySpec; class RebootEscrowManager { private static final String TAG = "RebootEscrowManager"; /** - * Used to track when the reboot escrow is wanted. Set to false when mRebootEscrowReady is - * true. + * Used to track when the reboot escrow is wanted. Should stay true once escrow is requested + * unless clearRebootEscrow is called. This will allow all the active users to be unlocked + * after reboot. */ - private final AtomicBoolean mRebootEscrowWanted = new AtomicBoolean(false); + private boolean mRebootEscrowWanted; /** Used to track when reboot escrow is ready. */ private boolean mRebootEscrowReady; @@ -54,10 +53,16 @@ class RebootEscrowManager { private RebootEscrowListener mRebootEscrowListener; /** + * Hold this lock when checking or generating the reboot escrow key. + */ + private final Object mKeyGenerationLock = new Object(); + + /** * Stores the reboot escrow data between when it's supplied and when * {@link #armRebootEscrowIfNeeded()} is called. */ - private RebootEscrowData mPendingRebootEscrowData; + @GuardedBy("mKeyGenerationLock") + private RebootEscrowKey mPendingRebootEscrowKey; private final UserManager mUserManager; @@ -82,6 +87,7 @@ class RebootEscrowManager { public Context getContext() { return mContext; } + public UserManager getUserManager() { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } @@ -123,13 +129,13 @@ class RebootEscrowManager { return; } - SecretKeySpec escrowKey = getAndClearRebootEscrowKey(); + RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(); if (escrowKey == null) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); } - StatsLog.write(StatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, false); + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, false); return; } @@ -137,10 +143,11 @@ class RebootEscrowManager { for (UserInfo user : rebootEscrowUsers) { allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey); } - StatsLog.write(StatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, allUsersUnlocked); + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, + allUsersUnlocked); } - private SecretKeySpec getAndClearRebootEscrowKey() { + private RebootEscrowKey getAndClearRebootEscrowKey() { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { return null; @@ -170,14 +177,14 @@ class RebootEscrowManager { // Overwrite the existing key with the null key rebootEscrow.storeKey(new byte[32]); - return RebootEscrowData.fromKeyBytes(escrowKeyBytes); + return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (RemoteException e) { Slog.w(TAG, "Could not retrieve escrow data"); return null; } } - private boolean restoreRebootEscrowForUser(@UserIdInt int userId, SecretKeySpec escrowKey) { + private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey key) { if (!mStorage.hasRebootEscrow(userId)) { return false; } @@ -186,7 +193,7 @@ class RebootEscrowManager { byte[] blob = mStorage.readRebootEscrow(userId); mStorage.removeRebootEscrow(userId); - RebootEscrowData escrowData = RebootEscrowData.fromEncryptedData(escrowKey, blob); + RebootEscrowData escrowData = RebootEscrowData.fromEncryptedData(key, blob); mCallbacks.onRebootEscrowRestored(escrowData.getSpVersion(), escrowData.getSyntheticPassword(), userId); @@ -199,33 +206,60 @@ class RebootEscrowManager { void callToRebootEscrowIfNeeded(@UserIdInt int userId, byte spVersion, byte[] syntheticPassword) { - if (!mRebootEscrowWanted.compareAndSet(true, false)) { + if (!mRebootEscrowWanted) { return; } IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { + mRebootEscrowWanted = false; + setRebootEscrowReady(false); + return; + } + + RebootEscrowKey escrowKey = generateEscrowKeyIfNeeded(); + if (escrowKey == null) { + Slog.e(TAG, "Could not generate escrow key"); + mRebootEscrowWanted = false; setRebootEscrowReady(false); return; } final RebootEscrowData escrowData; try { - escrowData = RebootEscrowData.fromSyntheticPassword(spVersion, syntheticPassword); + escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion, + syntheticPassword); } catch (IOException e) { setRebootEscrowReady(false); Slog.w(TAG, "Could not escrow reboot data", e); return; } - mPendingRebootEscrowData = escrowData; mStorage.writeRebootEscrow(userId, escrowData.getBlob()); setRebootEscrowReady(true); } + private RebootEscrowKey generateEscrowKeyIfNeeded() { + synchronized (mKeyGenerationLock) { + if (mPendingRebootEscrowKey != null) { + return mPendingRebootEscrowKey; + } + + RebootEscrowKey key; + try { + key = RebootEscrowKey.generate(); + } catch (IOException e) { + return null; + } + + mPendingRebootEscrowKey = key; + return key; + } + } + private void clearRebootEscrowIfNeeded() { - mRebootEscrowWanted.set(false); + mRebootEscrowWanted = false; setRebootEscrowReady(false); IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); @@ -255,14 +289,18 @@ class RebootEscrowManager { return false; } - RebootEscrowData escrowData = mPendingRebootEscrowData; - if (escrowData == null) { + RebootEscrowKey escrowKey; + synchronized (mKeyGenerationLock) { + escrowKey = mPendingRebootEscrowKey; + } + + if (escrowKey == null) { return false; } boolean armedRebootEscrow = false; try { - rebootEscrow.storeKey(escrowData.getKey()); + rebootEscrow.storeKey(escrowKey.getKeyBytes()); armedRebootEscrow = true; } catch (RemoteException e) { Slog.w(TAG, "Failed escrow secret to RebootEscrow HAL", e); @@ -283,7 +321,7 @@ class RebootEscrowManager { } clearRebootEscrowIfNeeded(); - mRebootEscrowWanted.set(true); + mRebootEscrowWanted = true; return true; } diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 8179c32ae2df..669f1ac6750c 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -186,6 +186,7 @@ class BluetoothRouteProvider { .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED) .setDescription(mContext.getResources().getText( R.string.bluetooth_a2dp_audio_route_name).toString()) + .setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH) .build(); newBtRoute.connectedProfiles = new SparseBooleanArray(); return newBtRoute; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 4ff37a2040dd..42bc464e943f 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -291,6 +291,14 @@ public abstract class ApexManager { public abstract boolean restoreCeData(int userId, int rollbackId, String apexPackageName); /** + * Deletes snapshots of the device encrypted apex data directories for the given + * {@code rollbackId}. + * + * @return boolean true if the delete was successful + */ + public abstract boolean destroyDeSnapshots(int rollbackId); + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -720,6 +728,17 @@ public abstract class ApexManager { } } + @Override + public boolean destroyDeSnapshots(int rollbackId) { + try { + mApexService.destroyDeSnapshots(rollbackId); + return true; + } catch (Exception e) { + Slog.e(TAG, e.getMessage(), e); + return false; + } + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -933,6 +952,11 @@ public abstract class ApexManager { } @Override + public boolean destroyDeSnapshots(int rollbackId) { + throw new UnsupportedOperationException(); + } + + @Override void dump(PrintWriter pw, String packageName) { // No-op } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 89f24d86192c..3ad120705eb3 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -347,6 +347,7 @@ public class AppsFilter { mForceQueryable.contains(newPkgSetting.appId) /* shared user that is already force queryable */ || newPkg.isForceQueryable() + || newPkgSetting.forceQueryableOverride || (newPkgSetting.isSystem() && (mSystemAppsQueryable || ArrayUtils.contains(mForceQueryableByDevicePackageNames, newPkg.getPackageName()))); diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java index 50cd0fcbbb17..4fc9e909a774 100644 --- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java +++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java @@ -225,9 +225,6 @@ public class DataLoaderManagerService extends SystemService { private void remove() { synchronized (mLock) { mServiceConnections.remove(mId); - if (mServiceConnections.size() == 0) { - mServiceConnections = null; - } } mParams.clear(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index c17ad1119631..9116c4032ad5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -635,6 +635,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements stageCid = buildExternalStageCid(sessionId); } } + + // reset the force queryable param if it's not called by an approved caller. + if (params.forceQueryableOverride) { + if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { + params.forceQueryableOverride = false; + } + } InstallSource installSource = InstallSource.create(installerPackageName, originatingPackageName, requestedInstallerPackageName); session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 148c5adbdce0..c09fb38c4d8a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -117,6 +117,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo; import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles; import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime; import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; +import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive; import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; import android.Manifest; @@ -361,7 +362,6 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -651,6 +651,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String[] INSTANT_APP_BROADCAST_PERMISSION = new String[] { android.Manifest.permission.ACCESS_INSTANT_APPS }; + private static final String RANDOM_DIR_PREFIX = "~~"; + final ServiceThread mHandlerThread; final PackageHandler mHandler; @@ -2996,9 +2998,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - //delete tmp files - deleteTempPackageFiles(); - final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get(); // Remove any shared userIDs that have no associated packages @@ -3591,8 +3590,7 @@ public class PackageManagerService extends IPackageManager.Stub getNextCodePath(Environment.getDataAppDirectory(null), packageName); int ret = PackageManager.INSTALL_SUCCEEDED; try { - Os.mkdir(dstCodePath.getAbsolutePath(), 0755); - Os.chmod(dstCodePath.getAbsolutePath(), 0755); + makeDirRecursive(dstCodePath, 0755); for (File srcFile : compressedFiles) { final String srcFileName = srcFile.getName(); final String dstFileName = srcFileName.substring( @@ -9852,8 +9850,12 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mInstallLock") void removeCodePathLI(File codePath) { if (codePath.isDirectory()) { + File codePathParent = codePath.getParentFile(); try { mInstaller.rmPackageDir(codePath.getAbsolutePath()); + if (codePathParent.getName().startsWith(RANDOM_DIR_PREFIX)) { + mInstaller.rmPackageDir(codePathParent.getAbsolutePath()); + } } catch (InstallerException e) { Slog.w(TAG, "Failed to remove code path", e); } @@ -10570,6 +10572,10 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting.sharedUser != null) { pkgSetting.sharedUser.addPackage(pkgSetting); } + if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) { + pkgSetting.forceQueryableOverride = true; + } + // TODO(toddke): Consider a method specifically for modifying the Package object // post scan; or, moving this stuff out of the Package object since it has nothing // to do with the package on disk. @@ -14063,6 +14069,7 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable MultiPackageInstallParams mParentInstallParams; final long requiredInstalledVersionCode; + final boolean forceQueryableOverride; InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, int installFlags, InstallSource installSource, String volumeUuid, @@ -14084,6 +14091,7 @@ public class PackageManagerService extends IPackageManager.Stub this.signingDetails = signingDetails; this.installReason = installReason; this.requiredInstalledVersionCode = requiredInstalledVersionCode; + this.forceQueryableOverride = false; } InstallParams(ActiveInstallSession activeInstallSession) { @@ -14117,6 +14125,7 @@ public class PackageManagerService extends IPackageManager.Stub signingDetails = activeInstallSession.getSigningDetails(); requiredInstalledVersionCode = activeInstallSession.getSessionParams() .requiredInstalledVersionCode; + forceQueryableOverride = activeInstallSession.getSessionParams().forceQueryableOverride; } @Override @@ -14717,6 +14726,7 @@ public class PackageManagerService extends IPackageManager.Stub final int traceCookie; final PackageParser.SigningDetails signingDetails; final int installReason; + final boolean forceQueryableOverride; @Nullable final MultiPackageInstallParams mMultiPackageInstallParams; // The list of instruction sets supported by this app. This is currently @@ -14730,7 +14740,7 @@ public class PackageManagerService extends IPackageManager.Stub String abiOverride, String[] installGrantPermissions, List<String> whitelistedRestrictedPermissions, String traceMethod, int traceCookie, SigningDetails signingDetails, - int installReason, + int installReason, boolean forceQueryableOverride, MultiPackageInstallParams multiPackageInstallParams) { this.origin = origin; this.move = move; @@ -14747,6 +14757,7 @@ public class PackageManagerService extends IPackageManager.Stub this.traceCookie = traceCookie; this.signingDetails = signingDetails; this.installReason = installReason; + this.forceQueryableOverride = forceQueryableOverride; this.mMultiPackageInstallParams = multiPackageInstallParams; } @@ -14757,7 +14768,7 @@ public class PackageManagerService extends IPackageManager.Stub params.getUser(), null /*instructionSets*/, params.packageAbiOverride, params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions, params.traceMethod, params.traceCookie, params.signingDetails, - params.installReason, params.mParentInstallParams); + params.installReason, params.forceQueryableOverride, params.mParentInstallParams); } abstract int copyApk(); @@ -14848,7 +14859,7 @@ public class PackageManagerService extends IPackageManager.Stub super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, instructionSets, null, null, null, null, 0, PackageParser.SigningDetails.UNKNOWN, - PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */); + PackageManager.INSTALL_REASON_UNKNOWN, false, null /* parent */); this.codeFile = (codePath != null) ? new File(codePath) : null; this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; } @@ -14926,7 +14937,9 @@ public class PackageManagerService extends IPackageManager.Stub final boolean onIncremental = mIncrementalManager != null && isIncrementalPath(beforeCodeFile.getAbsolutePath()); try { + makeDirRecursive(afterCodeFile.getParentFile(), 0775); if (onIncremental) { + // TODO(b/147371381): fix incremental installation mIncrementalManager.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); } else { @@ -15138,16 +15151,29 @@ public class PackageManagerService extends IPackageManager.Stub } } + /** + * Given {@code targetDir}, returns {@code targetDir/~~[randomStrA]/[packageName]-[randomStrB].} + * Makes sure that {@code targetDir/~~[randomStrA]} directory doesn't exist. + * Notice that this method doesn't actually create any directory. + * + * @param targetDir Directory that is two-levels up from the result directory. + * @param packageName Name of the package whose code files are to be installed under the result + * directory. + * @return File object for the directory that should hold the code files of {@code packageName}. + */ private File getNextCodePath(File targetDir, String packageName) { - File result; SecureRandom random = new SecureRandom(); byte[] bytes = new byte[16]; + File firstLevelDir; do { random.nextBytes(bytes); - String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); - result = new File(targetDir, packageName + "-" + suffix); - } while (result.exists()); - return result; + String dirName = RANDOM_DIR_PREFIX + + Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); + firstLevelDir = new File(targetDir, dirName); + } while (firstLevelDir.exists()); + random.nextBytes(bytes); + String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP); + return new File(firstLevelDir, packageName + "-" + suffix); } static class PackageInstalledInfo { @@ -17142,12 +17168,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void deleteTempPackageFiles() { - // TODO: Is this used? - final FilenameFilter filter = - (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp"); - } - @Override public void deletePackageAsUser(String packageName, int versionCode, IPackageDeleteObserver observer, int userId, int flags) { @@ -21477,7 +21497,7 @@ public class PackageManagerService extends IPackageManager.Stub final int absoluteCodePathCount = absoluteCodePaths.size(); for (int i = 0; i < absoluteCodePathCount; i++) { String absoluteCodePath = absoluteCodePaths.get(i); - if (absolutePath.startsWith(absoluteCodePath)) { + if (absoluteCodePath.startsWith(absolutePath)) { pathValid = true; break; } @@ -23835,9 +23855,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getRuntimePermissionsVersion(@UserIdInt int userId) { Preconditions.checkArgumentNonnegative(userId); - mContext.enforceCallingOrSelfPermission( - Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, - "setRuntimePermissionVersion"); + enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( + "getRuntimePermissionVersion"); synchronized (mLock) { return mSettings.getDefaultRuntimePermissionsVersionLPr(userId); } @@ -23847,14 +23866,27 @@ public class PackageManagerService extends IPackageManager.Stub public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) { Preconditions.checkArgumentNonnegative(version); Preconditions.checkArgumentNonnegative(userId); - mContext.enforceCallingOrSelfPermission( - Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, + enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( "setRuntimePermissionVersion"); synchronized (mLock) { mSettings.setDefaultRuntimePermissionsVersionLPr(version, userId); } } + private void enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions( + @NonNull String message) { + if (mContext.checkCallingOrSelfPermission( + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + != PackageManager.PERMISSION_GRANTED + && mContext.checkCallingOrSelfPermission( + Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException(message + " requires " + + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " or " + + Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS); + } + } + @Nullable public PackageSetting getPackageSetting(String packageName) { synchronized (mLock) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index ded9a9c58c5e..71a5545c4131 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -83,6 +83,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; +import java.nio.file.Path; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.text.SimpleDateFormat; @@ -918,4 +919,21 @@ public class PackageManagerServiceUtils { } return packageSetting.getPermissionsState(); } + + /** + * Recursively create target directory + */ + public static void makeDirRecursive(File targetDir, int mode) throws ErrnoException { + final Path targetDirPath = targetDir.toPath(); + final int directoriesCount = targetDirPath.getNameCount(); + File currentDir; + for (int i = 1; i <= directoriesCount; i++) { + currentDir = targetDirPath.subpath(0, i).toFile(); + if (currentDir.exists()) { + continue; + } + Os.mkdir(currentDir.getAbsolutePath(), mode); + Os.chmod(currentDir.getAbsolutePath(), mode); + } + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index e7f6b8982b04..bb69680fb9f9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2730,6 +2730,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--staged": sessionParams.setStaged(); break; + case "--force-queryable": + sessionParams.setForceQueryable(); + break; case "--enable-rollback": if (params.installerPackageName == null) { // com.android.shell has the TEST_MANAGE_ROLLBACKS diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index f1ac0afa5dfd..7d95b198d8ce 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -36,7 +36,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import java.io.File; import java.util.Arrays; @@ -132,6 +131,8 @@ public abstract class PackageSettingBase extends SettingBase { IntentFilterVerificationInfo verificationInfo; + boolean forceQueryableOverride; + PackageSettingBase(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, @@ -261,6 +262,7 @@ public abstract class PackageSettingBase extends SettingBase { ? Arrays.copyOf(orig.usesStaticLibrariesVersions, orig.usesStaticLibrariesVersions.length) : null; updateAvailable = orig.updateAvailable; + forceQueryableOverride = orig.forceQueryableOverride; } @VisibleForTesting @@ -693,6 +695,7 @@ public abstract class PackageSettingBase extends SettingBase { this.categoryHint = other.categoryHint; this.updateAvailable = other.updateAvailable; this.verificationInfo = other.verificationInfo; + this.forceQueryableOverride = other.forceQueryableOverride; if (mOldCodePaths != null) { if (other.mOldCodePaths != null) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 5d948b24256a..fcd8e221a9e8 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2836,6 +2836,9 @@ public final class Settings { if (pkg.updateAvailable) { serializer.attribute(null, "updateAvailable", "true"); } + if (pkg.forceQueryableOverride) { + serializer.attribute(null, "forceQueryable", "true"); + } writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); @@ -3599,6 +3602,7 @@ public final class Settings { PackageSetting packageSetting = null; String version = null; long versionCode = 0; + String installedForceQueryable = null; try { name = parser.getAttributeValue(null, ATTR_NAME); realName = parser.getAttributeValue(null, "realName"); @@ -3615,6 +3619,7 @@ public final class Settings { secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi"); cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride"); updateAvailable = parser.getAttributeValue(null, "updateAvailable"); + installedForceQueryable = parser.getAttributeValue(null, "forceQueryable"); if (primaryCpuAbiString == null && legacyCpuAbiString != null) { primaryCpuAbiString = legacyCpuAbiString; @@ -3798,6 +3803,7 @@ public final class Settings { packageSetting.primaryCpuAbiString = primaryCpuAbiString; packageSetting.secondaryCpuAbiString = secondaryCpuAbiString; packageSetting.updateAvailable = "true".equals(updateAvailable); + packageSetting.forceQueryableOverride = "true".equals(installedForceQueryable); // Handle legacy string here for single-user mode final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); if (enabledStr != null) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 5511a54de2cd..0cb8f49540be 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -932,6 +932,7 @@ public class UserManagerService extends IUserManager.Stub { userId, true /* enableQuietMode */, target, callingPackage); return true; } + mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId); boolean needToShowConfirmCredential = mLockPatternUtils.isSecure(userId) && !StorageManager.isUserKeyUnlocked(userId); @@ -942,8 +943,7 @@ public class UserManagerService extends IUserManager.Stub { showConfirmCredentialToDisableQuietMode(userId, target); return false; } - setQuietModeEnabled( - userId, false /* enableQuietMode */, target, callingPackage); + setQuietModeEnabled(userId, false /* enableQuietMode */, target, callingPackage); return true; } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index cb583cd42412..e0143ae4841b 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -44,6 +44,7 @@ import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.pm.ApexManager; import java.io.File; import java.io.IOException; @@ -651,15 +652,23 @@ class Rollback { */ void delete(AppDataRollbackHelper dataHelper) { synchronized (mLock) { + boolean containsApex = false; for (PackageRollbackInfo pkgInfo : info.getPackages()) { - IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers(); - for (int i = 0; i < snapshottedUsers.size(); i++) { - // Destroy app data snapshot. - int userId = snapshottedUsers.get(i); - - dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId); + if (pkgInfo.isApex()) { + containsApex = true; + } else { + IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers(); + for (int i = 0; i < snapshottedUsers.size(); i++) { + // Destroy app data snapshot. + int userId = snapshottedUsers.get(i); + + dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId); + } } } + if (containsApex) { + ApexManager.getInstance().destroyDeSnapshots(info.getRollbackId()); + } RollbackStore.deleteRollback(this); mState = ROLLBACK_STATE_DELETED; diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 4bab22478e6a..4425c0acba2a 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -52,6 +52,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.util.ArraySet; import android.util.IntArray; +import android.util.Log; import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseBooleanArray; @@ -94,7 +95,7 @@ import java.util.concurrent.TimeUnit; class RollbackManagerServiceImpl extends IRollbackManager.Stub { private static final String TAG = "RollbackManager"; - private static final boolean LOCAL_LOGV = false; + private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE); // Rollbacks expire after 14 days. private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS = diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 8893213d4a71..8d090f1b6fce 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,7 +16,7 @@ package com.android.server.rollback; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -38,9 +38,9 @@ import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.PackageWatchdog; import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; @@ -224,14 +224,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve saveStagedRollbackId(rollbackId); } WatchdogRollbackLogger.logEvent(logPackage, - StatsLog + FrameworkStatsLog .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } else if (sessionInfo.isStagedSessionFailed() && markStagedSessionHandled(rollbackId)) { WatchdogRollbackLogger.logEvent(logPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); mContext.unregisterReceiver(listener); @@ -337,7 +338,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve final VersionedPackage logPackage = logPackageTemp; WatchdogRollbackLogger.logEvent(logPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, + FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, reasonToLog, failedPackageToLog); final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, @@ -355,7 +356,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve logPackage); } else { WatchdogRollbackLogger.logEvent(logPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, reasonToLog, failedPackageToLog); } } else { @@ -363,7 +365,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve markStagedSessionHandled(rollback.getRollbackId()); } WatchdogRollbackLogger.logEvent(logPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, reasonToLog, failedPackageToLog); } }); diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java index 3c923e7d2e31..79e1a2912147 100644 --- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java +++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java @@ -16,11 +16,11 @@ package com.android.server.rollback; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; -import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; +import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,6 +36,7 @@ import android.util.Slog; import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.PackageWatchdog; import java.util.ArrayList; @@ -138,11 +139,13 @@ public final class WatchdogRollbackLogger { for (VersionedPackage oldLoggingPackage : oldLoggingPackages) { if (sessionInfo.isStagedSessionApplied()) { logEvent(oldLoggingPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } else if (sessionInfo.isStagedSessionFailed()) { logEvent(oldLoggingPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } @@ -186,13 +189,14 @@ public final class WatchdogRollbackLogger { private static String rollbackTypeToString(int type) { switch (type) { - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE: + case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE: return "ROLLBACK_INITIATE"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS: + case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS: return "ROLLBACK_SUCCESS"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE: + case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE: return "ROLLBACK_FAILURE"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED: + case FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED: return "ROLLBACK_BOOT_TRIGGERED"; default: return "UNKNOWN"; @@ -201,13 +205,15 @@ public final class WatchdogRollbackLogger { private static String rollbackReasonToString(int reason) { switch (reason) { - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH: + case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH: return "REASON_NATIVE_CRASH"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK: + case FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK: return "REASON_EXPLICIT_HEALTH_CHECK"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH: + case FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH: return "REASON_APP_CRASH"; - case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING: + case FrameworkStatsLog + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING: return "REASON_APP_NOT_RESPONDING"; default: return "UNKNOWN"; diff --git a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java index d77cf900a0a9..897aa14ebb64 100644 --- a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java +++ b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java @@ -23,7 +23,8 @@ import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import java.security.GeneralSecurityException; import java.util.Arrays; @@ -82,7 +83,7 @@ class GlobalSettingsConfigApplicator { return mVerifier.verifySignature(data, signature); } catch (GeneralSecurityException e) { Slog.e(TAG, "Failed to verify signature", e); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SECURITY_EXCEPTION; + mEvent.status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__SECURITY_EXCEPTION; return false; } } @@ -116,14 +117,14 @@ class GlobalSettingsConfigApplicator { mEvent.version = config.version; } catch (InvalidConfigException e) { Slog.e(TAG, "Failed to parse global settings from package " + mSourcePackage, e); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__INVALID_CONFIG; + mEvent.status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__INVALID_CONFIG; return; } int currentVersion = getCurrentConfigVersion(); if (currentVersion >= config.version) { Slog.i(TAG, "Global settings from package " + mSourcePackage + " is older than existing: " + config.version + "<=" + currentVersion); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__OLD_CONFIG; + mEvent.status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__OLD_CONFIG; return; } // We have new config! @@ -133,12 +134,12 @@ class GlobalSettingsConfigApplicator { config.getMatchingConfig(Build.VERSION.SDK_INT); if (matchedConfig == null) { Slog.i(TAG, "Settings is not applicable to current SDK version; ignoring"); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__NOT_APPLICABLE; + mEvent.status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__NOT_APPLICABLE; return; } Slog.i(TAG, "Updating global settings to version " + config.version); updateCurrentConfig(config.version, matchedConfig.values); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__APPLIED; + mEvent.status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__APPLIED; } } diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java index 146c51688531..a85764221de5 100644 --- a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java +++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java @@ -18,7 +18,8 @@ package com.android.server.signedconfig; import android.os.Build; import android.util.Slog; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; @@ -96,7 +97,8 @@ public class SignatureVerifier { try { signature = Base64.getDecoder().decode(base64Signature); } catch (IllegalArgumentException e) { - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_SIGNATURE; + mEvent.status = + FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_SIGNATURE; Slog.e(TAG, "Failed to base64 decode signature"); return false; } @@ -108,7 +110,8 @@ public class SignatureVerifier { if (DBG) Slog.w(TAG, "Trying to verify signature using debug key"); if (verifyWithPublicKey(mDebugKey, data, signature)) { Slog.i(TAG, "Verified config using debug key"); - mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__DEBUG; + mEvent.verifiedWith = + FrameworkStatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__DEBUG; return true; } else { if (DBG) Slog.i(TAG, "Config verification failed using debug key"); @@ -120,16 +123,19 @@ public class SignatureVerifier { if (mProdKey == null) { Slog.e(TAG, "No prod key; construction failed?"); mEvent.status = - StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT; + FrameworkStatsLog + .SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT; return false; } if (verifyWithPublicKey(mProdKey, data, signature)) { Slog.i(TAG, "Verified config using production key"); - mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__PRODUCTION; + mEvent.verifiedWith = + FrameworkStatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__PRODUCTION; return true; } else { if (DBG) Slog.i(TAG, "Verification failed using production key"); - mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED; + mEvent.status = + FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED; return false; } } diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java index 2f2062c6f2ee..c1adf936d79b 100644 --- a/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java +++ b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java @@ -15,24 +15,24 @@ */ package com.android.server.signedconfig; -import android.util.StatsLog; +import com.android.internal.util.FrameworkStatsLog; /** * Helper class to allow a SignedConfigReported event to be built up in stages. */ public class SignedConfigEvent { - public int type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__UNKNOWN_TYPE; - public int status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__UNKNOWN_STATUS; + public int type = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__TYPE__UNKNOWN_TYPE; + public int status = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__UNKNOWN_STATUS; public int version = 0; public String fromPackage = null; - public int verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__NO_KEY; + public int verifiedWith = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__NO_KEY; /** * Write this event to statslog. */ public void send() { - StatsLog.write(StatsLog.SIGNED_CONFIG_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.SIGNED_CONFIG_REPORTED, type, status, version, fromPackage, verifiedWith); } diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java index dc39542dc29f..037c82ad6593 100644 --- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java +++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java @@ -26,8 +26,8 @@ import android.content.pm.PackageManagerInternal; import android.net.Uri; import android.os.Bundle; import android.util.Slog; -import android.util.StatsLog; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import java.nio.charset.StandardCharsets; @@ -85,7 +85,7 @@ public class SignedConfigService { && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) { SignedConfigEvent event = new SignedConfigEvent(); try { - event.type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS; + event.type = FrameworkStatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS; event.fromPackage = packageName; String config = metaData.getString(KEY_GLOBAL_SETTINGS); String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE); @@ -95,7 +95,8 @@ public class SignedConfigService { } catch (IllegalArgumentException iae) { Slog.e(TAG, "Failed to base64 decode global settings config from " + packageName); - event.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG; + event.status = + FrameworkStatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG; return; } if (DBG) { diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java index b136ec754f59..734b71824490 100644 --- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java +++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java @@ -41,11 +41,11 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.DataUnit; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.SystemService; @@ -512,15 +512,15 @@ public class DeviceStorageMonitorService extends SystemService { notification.flags |= Notification.FLAG_NO_CLEAR; mNotifManager.notifyAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE, notification, UserHandle.ALL); - StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.LOW_STORAGE_STATE_CHANGED, Objects.toString(vol.getDescription()), - StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__ON); + FrameworkStatsLog.LOW_STORAGE_STATE_CHANGED__STATE__ON); } else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) { mNotifManager.cancelAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE, UserHandle.ALL); - StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.LOW_STORAGE_STATE_CHANGED, Objects.toString(vol.getDescription()), - StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__OFF); + FrameworkStatsLog.LOW_STORAGE_STATE_CHANGED__STATE__OFF); } } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index e95fc4a4a938..a1e643f15a8e 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -101,11 +101,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { private TimestampedValue<Long> mLastAutoSystemClockTimeSet; /** - * A mapping from phoneId to a time suggestion. We typically expect one or two mappings: devices - * will have a small number of telephony devices and phoneIds are assumed to be stable. + * A mapping from slotIndex to a time suggestion. We typically expect one or two mappings: + * devices will have a small number of telephony devices and slotIndexs are assumed to be + * stable. */ @GuardedBy("this") - private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId = + private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionBySlotIndex = new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE); @GuardedBy("this") @@ -155,7 +156,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } // Perform validation / input filtering and record the validated suggestion against the - // phoneId. + // slotIndex. if (!validateAndStorePhoneSuggestion(timeSuggestion)) { return; } @@ -202,7 +203,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { ipw.println("Phone suggestion history:"); ipw.increaseIndent(); // level 2 - mSuggestionByPhoneId.dump(ipw); + mSuggestionBySlotIndex.dump(ipw); ipw.decreaseIndent(); // level 2 ipw.println("Network suggestion history:"); @@ -223,8 +224,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return false; } - int phoneId = suggestion.getPhoneId(); - PhoneTimeSuggestion previousSuggestion = mSuggestionByPhoneId.get(phoneId); + int slotIndex = suggestion.getSlotIndex(); + PhoneTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex); if (previousSuggestion != null) { // We can log / discard suggestions with obvious issues with the reference time clock. if (previousSuggestion.getUtcTime() == null @@ -249,7 +250,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } // Store the latest suggestion. - mSuggestionByPhoneId.put(phoneId, suggestion); + mSuggestionBySlotIndex.put(slotIndex, suggestion); return true; } @@ -323,15 +324,15 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // // [1] https://en.wikipedia.org/wiki/NITZ // - // Generally, when there are suggestions from multiple phoneIds they should usually + // Generally, when there are suggestions from multiple slotIndexs they should usually // approximately agree. In cases where signals *are* inaccurate we don't want to vacillate - // between signals from two phoneIds. However, it is known for NITZ signals to be incorrect - // occasionally, which means we also don't want to stick forever with one phoneId. Without - // cross-referencing across sources (e.g. the current device time, NTP), or doing some kind - // of statistical analysis of consistency within and across phoneIds, we can't know which - // suggestions are more correct. + // between signals from two slotIndexs. However, it is known for NITZ signals to be + // incorrect occasionally, which means we also don't want to stick forever with one + // slotIndex. Without cross-referencing across sources (e.g. the current device time, NTP), + // or doing some kind of statistical analysis of consistency within and across slotIndexs, + // we can't know which suggestions are more correct. // - // For simplicity, we try to value recency, then consistency of phoneId. + // For simplicity, we try to value recency, then consistency of slotIndex. // // The heuristic works as follows: // Recency: The most recent suggestion from each phone is scored. The score is based on a @@ -339,20 +340,20 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { // bucket, thus applying a loose reference time ordering. The suggestion with the highest // score is used. // Consistency: If there a multiple suggestions with the same score, the suggestion with the - // lowest phoneId is always taken. + // lowest slotIndex is always taken. // // In the trivial case with a single ID this will just mean that the latest received // suggestion is used. PhoneTimeSuggestion bestSuggestion = null; int bestScore = PHONE_INVALID_SCORE; - for (int i = 0; i < mSuggestionByPhoneId.size(); i++) { - Integer phoneId = mSuggestionByPhoneId.keyAt(i); - PhoneTimeSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i); + for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) { + Integer slotIndex = mSuggestionBySlotIndex.keyAt(i); + PhoneTimeSuggestion candidateSuggestion = mSuggestionBySlotIndex.valueAt(i); if (candidateSuggestion == null) { // Unexpected - null suggestions should never be stored. - Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for phoneId." - + " phoneId=" + phoneId); + Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for slotIndex." + + " slotIndex=" + slotIndex); continue; } else if (candidateSuggestion.getUtcTime() == null) { // Unexpected - we do not store empty suggestions. @@ -372,10 +373,10 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { bestSuggestion = candidateSuggestion; bestScore = candidateScore; } else if (bestScore == candidateScore) { - // Tie! Use the suggestion with the lowest phoneId. - int candidatePhoneId = candidateSuggestion.getPhoneId(); - int bestPhoneId = bestSuggestion.getPhoneId(); - if (candidatePhoneId < bestPhoneId) { + // Tie! Use the suggestion with the lowest slotIndex. + int candidateSlotIndex = candidateSuggestion.getSlotIndex(); + int bestSlotIndex = bestSuggestion.getSlotIndex(); + if (candidateSlotIndex < bestSlotIndex) { bestSuggestion = candidateSuggestion; } } @@ -396,7 +397,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } // The score is based on the age since receipt. Suggestions are bucketed so two - // suggestions in the same bucket from different phoneIds are scored the same. + // suggestions in the same bucket from different slotIndexs are scored the same. long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis(); // Turn the age into a discrete value: 0 <= bucketIndex < PHONE_BUCKET_COUNT. @@ -560,8 +561,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { */ @VisibleForTesting @Nullable - public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) { - return mSuggestionByPhoneId.get(phoneId); + public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int slotIndex) { + return mSuggestionBySlotIndex.get(slotIndex); } /** diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index b4a439991dd9..b0e006908231 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -172,12 +172,12 @@ public class TimeZoneDetectorStrategy { private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */); /** - * A mapping from phoneId to a phone time zone suggestion. We typically expect one or two - * mappings: devices will have a small number of telephony devices and phoneIds are assumed to + * A mapping from slotIndex to a phone time zone suggestion. We typically expect one or two + * mappings: devices will have a small number of telephony devices and slotIndexs are assumed to * be stable. */ @GuardedBy("this") - private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionByPhoneId = + private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionBySlotIndex = new ArrayMapWithHistory<>(KEEP_PHONE_SUGGESTION_HISTORY_SIZE); /** @@ -205,7 +205,7 @@ public class TimeZoneDetectorStrategy { /** * Suggests a time zone for the device, or withdraws a previous suggestion if * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a - * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}. + * specific {@link PhoneTimeZoneSuggestion#getSlotIndex() phone}. * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a * suggestion. The strategy uses suggestions to decide whether to modify the device's time zone * setting and what to set it to. @@ -221,8 +221,8 @@ public class TimeZoneDetectorStrategy { QualifiedPhoneTimeZoneSuggestion scoredSuggestion = new QualifiedPhoneTimeZoneSuggestion(suggestion, score); - // Store the suggestion against the correct phoneId. - mSuggestionByPhoneId.put(suggestion.getPhoneId(), scoredSuggestion); + // Store the suggestion against the correct slotIndex. + mSuggestionBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion); // Now perform auto time zone detection. The new suggestion may be used to modify the time // zone setting. @@ -384,8 +384,9 @@ public class TimeZoneDetectorStrategy { // and find the best. Note that we deliberately do not look at age: the caller can // rate-limit so age is not a strong indicator of confidence. Instead, the callers are // expected to withdraw suggestions they no longer have confidence in. - for (int i = 0; i < mSuggestionByPhoneId.size(); i++) { - QualifiedPhoneTimeZoneSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i); + for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) { + QualifiedPhoneTimeZoneSuggestion candidateSuggestion = + mSuggestionBySlotIndex.valueAt(i); if (candidateSuggestion == null) { // Unexpected continue; @@ -396,10 +397,10 @@ public class TimeZoneDetectorStrategy { } else if (candidateSuggestion.score > bestSuggestion.score) { bestSuggestion = candidateSuggestion; } else if (candidateSuggestion.score == bestSuggestion.score) { - // Tie! Use the suggestion with the lowest phoneId. - int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId(); - int bestPhoneId = bestSuggestion.suggestion.getPhoneId(); - if (candidatePhoneId < bestPhoneId) { + // Tie! Use the suggestion with the lowest slotIndex. + int candidateSlotIndex = candidateSuggestion.suggestion.getSlotIndex(); + int bestSlotIndex = bestSuggestion.suggestion.getSlotIndex(); + if (candidateSlotIndex < bestSlotIndex) { bestSuggestion = candidateSuggestion; } } @@ -455,7 +456,7 @@ public class TimeZoneDetectorStrategy { ipw.println("Phone suggestion history:"); ipw.increaseIndent(); // level 2 - mSuggestionByPhoneId.dump(ipw); + mSuggestionBySlotIndex.dump(ipw); ipw.decreaseIndent(); // level 2 ipw.decreaseIndent(); // level 1 ipw.flush(); @@ -465,8 +466,8 @@ public class TimeZoneDetectorStrategy { * A method used to inspect strategy state during tests. Not intended for general use. */ @VisibleForTesting - public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) { - return mSuggestionByPhoneId.get(phoneId); + public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int slotIndex) { + return mSuggestionBySlotIndex.get(slotIndex); } /** diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 2ef0015f2b7d..0502d0bfa933 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -1212,7 +1212,7 @@ class ActivityMetricsLogger { final ProtoOutputStream protoOutputStream = new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object). - record.dumpDebug(protoOutputStream); + record.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL); final byte[] bytes = protoOutputStream.getBytes(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b05c25082f85..df6dfc4d8ffe 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -196,6 +196,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.TaskPersister.DEBUG; import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; @@ -311,6 +312,8 @@ import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; import com.android.server.wm.ActivityStack.ActivityState; +import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.utils.InsetUtils; @@ -4080,7 +4083,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction, @Nullable Runnable animationFinishedCallback) { + boolean isVoiceInteraction, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { if (mUseTransferredAnimation) { return false; } @@ -4158,7 +4162,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We aren't delayed anything, but exiting windows rely on the animation finished // callback being called in case the ActivityRecord was pretending to be delayed, // which we might have done because we were in closing/opening apps list. - onAnimationFinished(); + onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */); if (visible) { // The token was made immediately visible, there will be no entrance animation. // We need to inform the client the enter animation was finished. @@ -6054,8 +6058,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - protected void onAnimationFinished() { - super.onAnimationFinished(); + protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { + super.onAnimationFinished(type, anim); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished"); mTransit = TRANSIT_UNSET; @@ -7502,17 +7506,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Write all fields to an {@code ActivityRecordProto}. This assumes the * {@code ActivityRecordProto} is the outer-most proto data. */ - void dumpDebug(ProtoOutputStream proto) { + void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) { writeNameToProto(proto, NAME); - super.dumpDebug(proto, WINDOW_TOKEN, WindowTraceLogLevel.ALL); + super.dumpDebug(proto, WINDOW_TOKEN, logLevel); proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); - proto.write(IS_ANIMATING, isAnimating()); - if (mThumbnail != null) { + proto.write(IS_ANIMATING, isAnimating(PARENTS)); + if (mThumbnail != null){ mThumbnail.dumpDebug(proto, THUMBNAIL); } proto.write(FILLS_PARENT, mOccludesParent); proto.write(APP_STOPPED, mAppStopped); + proto.write(TRANSLUCENT, !occludesParent()); + proto.write(VISIBLE, mVisible); proto.write(VISIBLE_REQUESTED, mVisibleRequested); proto.write(CLIENT_VISIBLE, mClientVisible); proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); @@ -7535,24 +7541,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A writeIdentifierToProto(proto, IDENTIFIER); proto.write(STATE, mState.toString()); - proto.write(VISIBLE_REQUESTED, mVisibleRequested); proto.write(FRONT_OF_TASK, isRootOfTask()); if (hasProcess()) { proto.write(PROC_ID, app.getPid()); } - proto.write(TRANSLUCENT, !occludesParent()); - proto.write(VISIBLE, mVisible); } - public void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - dumpDebug(proto); - proto.end(token); - } - - /** - * Copied from old AppWindowToken. - */ @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { @@ -7562,36 +7556,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final long token = proto.start(fieldId); - writeNameToProto(proto, NAME); - super.dumpDebug(proto, WINDOW_TOKEN, logLevel); - proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); - proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); - proto.write(IS_ANIMATING, isAnimating(PARENTS)); - if (mThumbnail != null){ - mThumbnail.dumpDebug(proto, THUMBNAIL); - } - proto.write(FILLS_PARENT, mOccludesParent); - proto.write(APP_STOPPED, mAppStopped); - proto.write(VISIBLE_REQUESTED, mVisibleRequested); - proto.write(CLIENT_VISIBLE, mClientVisible); - proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); - proto.write(REPORTED_DRAWN, reportedDrawn); - proto.write(REPORTED_VISIBLE, reportedVisible); - proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows); - proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows); - proto.write(ALL_DRAWN, allDrawn); - proto.write(LAST_ALL_DRAWN, mLastAllDrawn); - if (startingWindow != null) { - startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW); - } - proto.write(STARTING_DISPLAYED, startingDisplayed); - proto.write(STARTING_MOVED, startingMoved); - proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW, - mVisibleSetFromTransferredStartingWindow); - for (Rect bounds : mFrozenBounds) { - bounds.dumpDebug(proto, FROZEN_BOUNDS); - } - proto.write(VISIBLE, mVisible); + dumpDebug(proto, logLevel); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 0d72d84d1649..d5961a881c36 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -60,10 +60,18 @@ import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; -import static com.android.server.am.ActivityStackProto.DISPLAY_ID; -import static com.android.server.am.ActivityStackProto.FULLSCREEN; -import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; -import static com.android.server.am.ActivityStackProto.STACK; +import static com.android.server.wm.TaskProto.ACTIVITIES; +import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; +import static com.android.server.wm.TaskProto.BOUNDS; +import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS; +import static com.android.server.wm.TaskProto.DISPLAY_ID; +import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; +import static com.android.server.wm.TaskProto.MIN_HEIGHT; +import static com.android.server.wm.TaskProto.MIN_WIDTH; +import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; +import static com.android.server.wm.TaskProto.REAL_ACTIVITY; +import static com.android.server.wm.TaskProto.RESIZE_MODE; +import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; @@ -107,15 +115,19 @@ import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGE import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; -import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS; -import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME; -import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT; -import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT; -import static com.android.server.wm.StackProto.ANIMATING_BOUNDS; -import static com.android.server.wm.StackProto.DEFER_REMOVAL; -import static com.android.server.wm.StackProto.FILLS_PARENT; -import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT; -import static com.android.server.wm.StackProto.WINDOW_CONTAINER; +import static com.android.server.wm.TaskProto.ADJUSTED_BOUNDS; +import static com.android.server.wm.TaskProto.ADJUSTED_FOR_IME; +import static com.android.server.wm.TaskProto.ADJUST_DIVIDER_AMOUNT; +import static com.android.server.wm.TaskProto.ADJUST_IME_AMOUNT; +import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS; +import static com.android.server.wm.TaskProto.DEFER_REMOVAL; +import static com.android.server.wm.TaskProto.FILLS_PARENT; +import static com.android.server.wm.TaskProto.MINIMIZE_AMOUNT; +import static com.android.server.wm.TaskProto.ROOT_TASK_ID; +import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; +import static com.android.server.wm.TaskProto.SURFACE_WIDTH; +import static com.android.server.wm.TaskProto.TASKS; +import static com.android.server.wm.TaskProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -4925,49 +4937,66 @@ class ActivityStack extends Task implements BoundsAnimationTarget { @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { + if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { + return; + } + final long token = proto.start(fieldId); - dumpDebugInnerStackOnly(proto, STACK, logLevel); - proto.write(com.android.server.am.ActivityStackProto.ID, getRootTaskId()); + super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); + + proto.write(TaskProto.ID, mTaskId); + proto.write(DISPLAY_ID, getDisplayId()); + proto.write(ROOT_TASK_ID, getRootTaskId()); + + for (int i = mChildren.size() - 1; i >= 0; --i) { + final WindowContainer child = mChildren.get(i); + if (child instanceof Task) { + child.dumpDebug(proto, TASKS, logLevel); + } else if (child instanceof ActivityRecord) { + child.dumpDebug(proto, ACTIVITIES, logLevel); + } else { + throw new IllegalStateException("Unknown child type: " + child); + } + } - forAllTasks((t) -> { - t.dumpDebugInner(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel); - }, true /* traverseTopToBottom */, this); if (mResumedActivity != null) { mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); } - proto.write(DISPLAY_ID, getDisplayId()); - if (!matchParentBounds()) { - final Rect bounds = getRequestedOverrideBounds(); - bounds.dumpDebug(proto, com.android.server.am.ActivityStackProto.BOUNDS); + if (realActivity != null) { + proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); + } + if (origActivity != null) { + proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); } + proto.write(ACTIVITY_TYPE, getActivityType()); + proto.write(RESIZE_MODE, mResizeMode); + proto.write(MIN_WIDTH, mMinWidth); + proto.write(MIN_HEIGHT, mMinHeight); - // TODO: Remove, no longer needed with windowingMode. - proto.write(FULLSCREEN, matchParentBounds()); - proto.end(token); - } + proto.write(FILLS_PARENT, matchParentBounds()); - // TODO(proto-merge): Remove once protos for ActivityStack and TaskStack are merged. - void dumpDebugInnerStackOnly(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { - if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { - return; + if (!matchParentBounds()) { + final Rect bounds = getRequestedOverrideBounds(); + bounds.dumpDebug(proto, BOUNDS); + } + getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS); + mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS); + if (mLastNonFullscreenBounds != null) { + mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); } - final long token = proto.start(fieldId); - super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); - proto.write(StackProto.ID, getRootTaskId()); - forAllTasks((t) -> { - t.dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel); - }, true /* traverseTopToBottom */, this); - proto.write(FILLS_PARENT, matchParentBounds()); - getRawBounds().dumpDebug(proto, StackProto.BOUNDS); proto.write(DEFER_REMOVAL, mDeferRemoval); proto.write(MINIMIZE_AMOUNT, mMinimizeAmount); proto.write(ADJUSTED_FOR_IME, mAdjustedForIme); proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount); proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount); - mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS); proto.write(ANIMATING_BOUNDS, mBoundsAnimating); + + if (mSurfaceControl != null) { + proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); + proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + } + proto.end(token); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index d6e707795d50..5a5976bf58ad 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -69,6 +69,7 @@ import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; import static com.android.server.am.ActivityManagerService.dumpStackTraces; +import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONTROLLER; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER; @@ -257,7 +258,6 @@ import com.android.server.SystemServiceManager; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; -import com.android.server.am.ActivityManagerServiceDumpActivitiesProto; import com.android.server.am.ActivityManagerServiceDumpProcessesProto; import com.android.server.am.AppTimeTracker; import com.android.server.am.BaseErrorDialog; @@ -6963,10 +6963,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void writeActivitiesToProto(ProtoOutputStream proto) { synchronized (mGlobalLock) { // The output proto of "activity --proto activities" - // is ActivityManagerServiceDumpActivitiesProto - mRootWindowContainer.dumpDebug(proto, - ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR, - WindowTraceLogLevel.ALL); + mRootWindowContainer.dumpDebug( + proto, ROOT_WINDOW_CONTAINER, WindowTraceLogLevel.ALL); } } diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 1be3d614de33..0519b80c732a 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -21,6 +21,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -47,9 +48,10 @@ interface AnimationAdapter { * component running the animation after {@code finishCallback} has been * invoked, or after the animation was cancelled. * @param t The Transaction to apply the initial frame of the animation. + * @param type The type of the animation. * @param finishCallback The callback to be invoked when the animation has finished. */ - void startAnimation(SurfaceControl animationLeash, Transaction t, + void startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type, OnAnimationFinishedCallback finishCallback); /** diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 0798a910c860..f72020ea8988 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -377,9 +377,9 @@ public class AppTransitionController { transitioningDecendants.add(app); } } - wc.applyAnimation(animLp, transit, visible, voiceInteraction, () -> { + wc.applyAnimation(animLp, transit, visible, voiceInteraction, (type, anim) -> { for (int j = 0; j < transitioningDecendants.size(); ++j) { - transitioningDecendants.get(j).onAnimationFinished(); + transitioningDecendants.get(j).onAnimationFinished(type, anim); } }); } diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index 16aff9c10c7d..537ca08f49fc 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -20,6 +20,7 @@ import static com.android.server.wm.AlphaAnimationSpecProto.DURATION_MS; import static com.android.server.wm.AlphaAnimationSpecProto.FROM; import static com.android.server.wm.AlphaAnimationSpecProto.TO; import static com.android.server.wm.AnimationSpecProto.ALPHA; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; import android.annotation.Nullable; import android.graphics.Rect; @@ -29,6 +30,8 @@ import android.view.Surface; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -135,7 +138,7 @@ class Dimmer { mDimLayer = dimLayer; mDimming = true; final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); - mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> { + mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, (type, anim) -> { if (!mDimming) { dimAnimatable.removeSurface(); } @@ -157,8 +160,8 @@ class Dimmer { @VisibleForTesting interface SurfaceAnimatorStarter { void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, - @Nullable Runnable animationFinishedCallback); + AnimationAdapter anim, boolean hidden, @AnimationType int type, + @Nullable OnAnimationFinishedCallback animationFinishedCallback); } Dimmer(WindowContainer host) { @@ -345,7 +348,7 @@ class Dimmer { mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter( new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */, - null /* animationFinishedCallback */); + ANIMATION_TYPE_DIMMER, null /* animationFinishedCallback */); } private long getDimDuration(WindowContainer container) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 81af0fe24ba7..16ac9fb41f30 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_STACK_ID; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -83,10 +84,9 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_TASK_OPEN; import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; -import static com.android.server.am.ActivityDisplayProto.DISPLAY; -import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID; -import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; -import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE; +import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID; +import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY; +import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -111,7 +111,7 @@ import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS; import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; -import static com.android.server.wm.DisplayContentProto.STACKS; +import static com.android.server.wm.DisplayContentProto.TASKS; import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; @@ -2733,30 +2733,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { - final long token = proto.start(fieldId); - dumpDebugInner(proto, DISPLAY, logLevel); - proto.write(com.android.server.am.ActivityDisplayProto.ID, mDisplayId); - proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance); - final ActivityStack focusedStack = getFocusedStack(); - if (focusedStack != null) { - proto.write(FOCUSED_STACK_ID, focusedStack.getRootTaskId()); - final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity(); - if (focusedActivity != null) { - focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); - } - } else { - proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); - } - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getStackAt(stackNdx); - stack.dumpDebug(proto, com.android.server.am.ActivityDisplayProto.STACKS, logLevel); - } - proto.end(token); - } - - // TODO(proto-merge): Remove once protos for ActivityDisplay and DisplayContent are merged. - public void dumpDebugInner(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { // Critical log level logs only visible elements to mitigate performance overheard if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { return; @@ -2764,11 +2740,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final long token = proto.start(fieldId); super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); + proto.write(ID, mDisplayId); mRootDisplayArea.dumpDebug(proto, ROOT_DISPLAY_AREA, logLevel); - for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mTaskContainers.getChildAt(stackNdx); - stack.dumpDebugInnerStackOnly(proto, STACKS, logLevel); + for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) { + final ActivityStack stack = mTaskContainers.getChildAt(i); + stack.dumpDebug(proto, TASKS, logLevel); } mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER); for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) { @@ -2796,6 +2773,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo for (int i = mChangingApps.size() - 1; i >= 0; i--) { mChangingApps.valueAt(i).writeIdentifierToProto(proto, CHANGING_APPS); } + + proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance); + final ActivityStack focusedStack = getFocusedStack(); + if (focusedStack != null) { + proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId()); + final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity(); + if (focusedActivity != null) { + focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); + } + } else { + proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID); + } + proto.end(token); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 40c335b0592b..c78707a2204e 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -335,6 +335,13 @@ public class DisplayPolicy { IApplicationToken mFocusedApp; + // The states of decor windows from the last layout. These are used to generate another display + // layout in different bounds but with the same states. + private boolean mLastNavVisible; + private boolean mLastNavTranslucent; + private boolean mLastNavAllowedHidden; + private boolean mLastNotificationShadeForcesShowingNavigation; + int mLastSystemUiFlags; // Bits that we are in the process of clearing, so we want to prevent // them from being set by applications until everything has been updated @@ -1425,6 +1432,46 @@ public class DisplayPolicy { } } + private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames, int uiMode, + InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) { + win.setSimulatedWindowFrames(simulatedWindowFrames); + try { + layout.run(); + } finally { + win.setSimulatedWindowFrames(null); + } + mDisplayContent.getInsetsStateController().computeSimulatedState(insetsState, win, + displayFrames, simulatedWindowFrames); + } + + /** + * Computes the frames of display (its logical size, rotation and cutout should already be set) + * used to layout window. The result of display frames and insets state should be the same as + * using {@link #beginLayoutLw}, but this method only changes the given display frames, insets + * state and some temporal states. In other words, it doesn't change the window frames used to + * show on screen. + */ + void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) { + displayFrames.onBeginLayout(); + final WindowFrames simulatedWindowFrames = new WindowFrames(); + if (mNavigationBar != null) { + simulateLayoutDecorWindow( + mNavigationBar, displayFrames, uiMode, insetsState, simulatedWindowFrames, + () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible, + mLastNavTranslucent, mLastNavAllowedHidden, + mLastNotificationShadeForcesShowingNavigation, + false /* isRealLayout */)); + } + if (mStatusBar != null) { + simulateLayoutDecorWindow( + mStatusBar, displayFrames, uiMode, insetsState, simulatedWindowFrames, + () -> layoutStatusBar(displayFrames, mLastSystemUiFlags, + false /* isRealLayout */)); + } + layoutScreenDecorWindows(displayFrames, simulatedWindowFrames); + postAdjustDisplayFrames(displayFrames); + } + /** * Called when layout of the windows is about to start. * @@ -1483,14 +1530,23 @@ public class DisplayPolicy { navVisible |= !canHideNavigationBar(); boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible, - navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation); + navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation, + true /* isRealLayout */); if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock); - updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing); + updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, true /* isRealLayout */); if (updateSysUiVisibility) { updateSystemUiVisibilityLw(); } - layoutScreenDecorWindows(displayFrames); + layoutScreenDecorWindows(displayFrames, null /* transientFrames */); + postAdjustDisplayFrames(displayFrames); + mLastNavVisible = navVisible; + mLastNavTranslucent = navTranslucent; + mLastNavAllowedHidden = navAllowedHidden; + mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation; + } + /** Enforces the last layout policy for display frames. */ + private void postAdjustDisplayFrames(DisplayFrames displayFrames) { if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) { // Make sure that the zone we're avoiding for the cutout is at least as tall as the // status bar; otherwise fullscreen apps will end up cutting halfway into the status @@ -1509,7 +1565,15 @@ public class DisplayPolicy { displayFrames.mContent.inset(mForwardedInsets); } - private void layoutScreenDecorWindows(DisplayFrames displayFrames) { + /** + * Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}. + * + * @param displayFrames The display frames to be layouted. + * @param simulatedFrames Non-null if the caller only needs the result of display frames (see + * {@link WindowState#mSimulatedWindowFrames}). + */ + private void layoutScreenDecorWindows(DisplayFrames displayFrames, + WindowFrames simulatedFrames) { if (mScreenDecorWindows.isEmpty()) { return; } @@ -1527,17 +1591,24 @@ public class DisplayPolicy { continue; } - w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */, + final boolean isSimulatedLayout = simulatedFrames != null; + if (isSimulatedLayout) { + w.setSimulatedWindowFrames(simulatedFrames); + } + final WindowFrames windowFrames = w.getLayoutingWindowFrames(); + windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */, displayFrames.mUnrestricted /* displayFrame */, displayFrames.mUnrestricted /* contentFrame */, displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */, displayFrames.mUnrestricted /* stableFrame */); - w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); - w.computeFrameLw(); - if (w.getControllableInsetProvider() != null) { - w.getControllableInsetProvider().updateSourceFrame(); + try { + w.computeFrame(displayFrames); + } finally { + if (isSimulatedLayout) { + w.setSimulatedWindowFrames(null); + } } - final Rect frame = w.getFrameLw(); + final Rect frame = windowFrames.mFrame; if (frame.left <= 0 && frame.top <= 0) { // Docked at left or top. @@ -1580,29 +1651,21 @@ public class DisplayPolicy { displayFrames.mContent.set(dockFrame); } - private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, - boolean isKeyguardShowing) { + private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isRealLayout) { // decide where the status bar goes ahead of time if (mStatusBar == null) { return false; } // apply any navigation bar insets sTmpRect.setEmpty(); - final WindowFrames windowFrames = mStatusBar.getWindowFrames(); + final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames(); windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */, displayFrames.mUnrestricted /* displayFrame */, displayFrames.mStable /* contentFrame */, displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */, displayFrames.mStable /* stableFrame */); - windowFrames.setDisplayCutout(displayFrames.mDisplayCutout); - // Let the status bar determine its size. - mStatusBar.computeFrameLw(); - - // Update the source frame to provide insets to other windows during layout. - if (mStatusBar.getControllableInsetProvider() != null) { - mStatusBar.getControllableInsetProvider().updateSourceFrame(); - } + mStatusBar.computeFrame(displayFrames); // For layout, the status bar is always at the top with our fixed height. displayFrames.mStable.top = displayFrames.mUnrestricted.top @@ -1611,12 +1674,14 @@ public class DisplayPolicy { displayFrames.mStable.top = Math.max(displayFrames.mStable.top, displayFrames.mDisplayCutoutSafe.top); - // Tell the bar controller where the collapsed status bar content is - sTmpRect.set(mStatusBar.getContentFrameLw()); - sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); - sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset - sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size - mStatusBarController.setContentFrame(sTmpRect); + if (isRealLayout) { + // Tell the bar controller where the collapsed status bar content is. + sTmpRect.set(windowFrames.mContentFrame); + sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); + sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset + sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size + mStatusBarController.setContentFrame(sTmpRect); + } boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0 || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR); @@ -1651,7 +1716,7 @@ public class DisplayPolicy { private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible, boolean navTranslucent, boolean navAllowedHidden, - boolean statusBarForcesShowingNavigation) { + boolean statusBarForcesShowingNavigation, boolean isRealLayout) { if (mNavigationBar == null) { return false; } @@ -1665,13 +1730,13 @@ public class DisplayPolicy { final int displayHeight = displayFrames.mDisplayHeight; final int displayWidth = displayFrames.mDisplayWidth; final Rect dockFrame = displayFrames.mDock; - mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation); + final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation); final Rect cutoutSafeUnrestricted = sTmpRect; cutoutSafeUnrestricted.set(displayFrames.mUnrestricted); cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe); - if (mNavigationBarPosition == NAV_BAR_BOTTOM) { + if (navBarPosition == NAV_BAR_BOTTOM) { // It's a system nav bar or a portrait screen; nav bar goes on bottom. final int top = cutoutSafeUnrestricted.bottom - getNavigationBarHeight(rotation, uiMode); @@ -1695,7 +1760,7 @@ public class DisplayPolicy { // of animating on or off, then we can tell the app that it is covered by it. displayFrames.mSystem.bottom = top; } - } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { + } else if (navBarPosition == NAV_BAR_RIGHT) { // Landscape screen; nav bar goes to the right. final int left = cutoutSafeUnrestricted.right - getNavigationBarWidth(rotation, uiMode); @@ -1717,7 +1782,7 @@ public class DisplayPolicy { // animating on or off, then we can tell the app that it is covered by it. displayFrames.mSystem.right = left; } - } else if (mNavigationBarPosition == NAV_BAR_LEFT) { + } else if (navBarPosition == NAV_BAR_LEFT) { // Seascape screen; nav bar goes to the left. final int right = cutoutSafeUnrestricted.left + getNavigationBarWidth(rotation, uiMode); @@ -1748,17 +1813,17 @@ public class DisplayPolicy { displayFrames.mContent.set(dockFrame); // And compute the final frame. sTmpRect.setEmpty(); - mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */, + final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames(); + windowFrames.setFrames(navigationFrame /* parentFrame */, navigationFrame /* displayFrame */, displayFrames.mDisplayCutoutSafe /* contentFrame */, navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */, navigationFrame /* stableFrame */); - mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); - mNavigationBar.computeFrameLw(); - if (mNavigationBar.getControllableInsetProvider() != null) { - mNavigationBar.getControllableInsetProvider().updateSourceFrame(); + mNavigationBar.computeFrame(displayFrames); + if (isRealLayout) { + mNavigationBarPosition = navBarPosition; + mNavigationBarController.setContentFrame(windowFrames.mContentFrame); } - mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame); return mNavigationBarController.checkHiddenLw(); @@ -1886,7 +1951,6 @@ public class DisplayPolicy { final Rect sf = windowFrames.mStableFrame; dcf.setEmpty(); windowFrames.setParentFrameWasClippedByDisplayCutout(false); - windowFrames.setDisplayCutout(displayFrames.mDisplayCutout); final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null && mNavigationBar.isVisibleLw(); @@ -2311,10 +2375,7 @@ public class DisplayPolicy { windowFrames.setContentChanged(true); } - win.computeFrameLw(); - if (win.getControllableInsetProvider() != null) { - win.getControllableInsetProvider().updateSourceFrame(); - } + win.computeFrame(displayFrames); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (type == TYPE_INPUT_METHOD && win.isVisibleLw() diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 0291017cd039..884f7694d648 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -20,8 +20,10 @@ package com.android.server.wm; import android.annotation.Nullable; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.view.IWindow; +import android.view.InputApplicationHandle; /** * Keeps track of embedded windows. @@ -44,21 +46,12 @@ class EmbeddedWindowController { * * @param inputToken input channel token passed in by the embedding process when it requests * the server to add an input channel to the embedded surface. - * @param window client token used to clean up the map if the embedding process dies - * @param hostWindowState input channel token belonging to the host window. This is needed to - * handle input callbacks to wm. It's used when raising ANR and when - * the user taps out side of the focused region on screen. This can be - * null if there is no host window. - * @param ownerUid calling uid - * @param ownerPid calling pid used for anr blaming + * @param embeddedWindow An {@link EmbeddedWindow} object to add to this controller. */ - void add(IBinder inputToken, IWindow window, @Nullable WindowState hostWindowState, - int ownerUid, int ownerPid) { - EmbeddedWindow embeddedWindow = new EmbeddedWindow(window, hostWindowState, ownerUid, - ownerPid); + void add(IBinder inputToken, EmbeddedWindow embeddedWindow) { try { mWindows.put(inputToken, embeddedWindow); - window.asBinder().linkToDeath(()-> { + embeddedWindow.mClient.asBinder().linkToDeath(()-> { synchronized (mWmLock) { mWindows.remove(inputToken); } @@ -101,6 +94,15 @@ class EmbeddedWindowController { final int mOwnerUid; final int mOwnerPid; + /** + * @param clientToken client token used to clean up the map if the embedding process dies + * @param hostWindowState input channel token belonging to the host window. This is needed + * to handle input callbacks to wm. It's used when raising ANR and + * when the user taps out side of the focused region on screen. This + * can be null if there is no host window. + * @param ownerUid calling uid + * @param ownerPid calling pid used for anr blaming + */ EmbeddedWindow(IWindow clientToken, WindowState hostWindowState, int ownerUid, int ownerPid) { mClient = clientToken; @@ -108,5 +110,21 @@ class EmbeddedWindowController { mOwnerUid = ownerUid; mOwnerPid = ownerPid; } + + String getName() { + final String hostWindowName = (mHostWindowState != null) + ? mHostWindowState.getWindowTag().toString() : "Internal"; + return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName + + "}"; + } + + InputApplicationHandle getApplicationHandle() { + if (mHostWindowState == null + || mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) { + return null; + } + return new InputApplicationHandle( + mHostWindowState.mInputWindowHandle.inputApplicationHandle); + } } } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index db434800c979..0418afaf033a 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.ViewRootImpl.sNewInsetsMode; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL; import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED; import android.annotation.NonNull; @@ -34,11 +35,11 @@ import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; -import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.util.function.TriConsumer; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -185,6 +186,17 @@ class InsetsSourceProvider { } } + /** @return A new source computed by the specified window frame in the given display frames. */ + InsetsSource createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames) { + final InsetsSource source = new InsetsSource(mSource); + mTmpRect.set(windowFrames.mFrame); + if (mFrameProvider != null) { + mFrameProvider.accept(displayFrames, mWin, mTmpRect); + } + source.setFrame(mTmpRect); + return source; + } + /** * Called when a layout pass has occurred. */ @@ -243,7 +255,8 @@ class InsetsSourceProvider { mAdapter = new ControlAdapter(); setClientVisible(InsetsState.getDefaultVisibility(mSource.getType())); final Transaction t = mDisplayContent.getPendingTransaction(); - mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */); + mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */, + ANIMATION_TYPE_INSETS_CONTROL, null /* animationFinishedCallback */); final SurfaceControl leash = mAdapter.mCapturedLeash; final long frameNumber = mFinishSeamlessRotateFrameNumber; mFinishSeamlessRotateFrameNumber = -1; @@ -348,7 +361,7 @@ class InsetsSourceProvider { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, OnAnimationFinishedCallback finishCallback) { // TODO(b/118118435): We can remove the type check when implementing the transient bar // animation. if (mSource.getType() == ITYPE_IME) { diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 289ac4cd5d44..caaa4305406c 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -179,6 +179,24 @@ class InsetsStateController { } } + /** + * Computes insets state of the insets provider window in the display frames. + * + * @param state The output state. + * @param win The owner window of insets provider. + * @param displayFrames The display frames to create insets source. + * @param windowFrames The specified frames to represent the owner window. + */ + void computeSimulatedState(InsetsState state, WindowState win, DisplayFrames displayFrames, + WindowFrames windowFrames) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + final InsetsSourceProvider provider = mProviders.valueAt(i); + if (provider.mWin == win) { + state.addSource(provider.createSimulatedSource(displayFrames, windowFrames)); + } + } + } + boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) { return mTypeFakeControlTargetMap.get(type) == target; } diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index ad65e101fd15..00947d766e89 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -31,11 +31,11 @@ import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; -import static com.android.server.am.KeyguardControllerProto.AOD_SHOWING; -import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES; -import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING; -import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID; -import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED; +import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING; +import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES; +import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING; +import static com.android.server.wm.KeyguardOccludedProto.DISPLAY_ID; +import static com.android.server.wm.KeyguardOccludedProto.KEYGUARD_OCCLUDED; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java index 5892239edb4d..7c1a6161236a 100644 --- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java @@ -24,6 +24,7 @@ import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -50,9 +51,9 @@ class LocalAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, OnAnimationFinishedCallback finishCallback) { mAnimator.startAnimation(mSpec, animationLeash, t, - () -> finishCallback.onAnimationFinished(this)); + () -> finishCallback.onAnimationFinished(type, this)); } @Override diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index da9d074eb7bc..944e0ae3d73f 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -30,6 +30,7 @@ import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.BoundsAnimationController.FADE_IN; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; import android.annotation.IntDef; @@ -61,6 +62,7 @@ import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; @@ -432,7 +434,8 @@ public class RecentsAnimationController implements DeathRecipient { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName()); final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task, isRecentTaskInvisible); - task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */); + task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */, + ANIMATION_TYPE_RECENTS); task.commitPendingTransaction(); mPendingAnimations.add(taskAdapter); return taskAdapter; @@ -443,14 +446,16 @@ public class RecentsAnimationController implements DeathRecipient { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeAnimation(%d)", taskAdapter.mTask.mTaskId); taskAdapter.mTask.setCanAffectSystemUiFlags(true); - taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter); + taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType, + taskAdapter); mPendingAnimations.remove(taskAdapter); } @VisibleForTesting void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeWallpaperAnimation()"); - wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter); + wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished( + wallpaperAdapter.getLastAnimationType(), wallpaperAdapter); mPendingWallpaperAnimations.remove(wallpaperAdapter); } @@ -638,7 +643,7 @@ public class RecentsAnimationController implements DeathRecipient { taskSnapshot.getColorSpace(), false /* containsSecureLayers */)); mRecentScreenshotAnimator = new SurfaceAnimator( animatable, - () -> { + (type, anim) -> { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish"); mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */); }, mService); @@ -827,6 +832,7 @@ public class RecentsAnimationController implements DeathRecipient { private final Task mTask; private SurfaceControl mCapturedLeash; private OnAnimationFinishedCallback mCapturedFinishCallback; + private @AnimationType int mLastAnimationType; private final boolean mIsRecentTaskInvisible; private RemoteAnimationTarget mTarget; private final Point mPosition = new Point(); @@ -868,7 +874,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, OnAnimationFinishedCallback finishCallback) { // Restore z-layering, position and stack crop until client has a chance to modify it. t.setLayer(animationLeash, mTask.getPrefixOrderIndex()); t.setPosition(animationLeash, mPosition.x, mPosition.y); @@ -877,6 +883,7 @@ public class RecentsAnimationController implements DeathRecipient { t.setWindowCrop(animationLeash, mTmpRect); mCapturedLeash = animationLeash; mCapturedFinishCallback = finishCallback; + mLastAnimationType = type; } @Override diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 6f7eeabfc4cd..d2dbab841f16 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -40,6 +40,7 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.util.FastPrintWriter; import com.android.server.protolog.ProtoLogImpl; import com.android.server.protolog.common.ProtoLog; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -180,12 +181,14 @@ class RemoteAnimationController implements DeathRecipient { if (wrappers.mAdapter != null && wrappers.mAdapter.mCapturedFinishCallback != null) { wrappers.mAdapter.mCapturedFinishCallback - .onAnimationFinished(wrappers.mAdapter); + .onAnimationFinished(wrappers.mAdapter.mAnimationType, + wrappers.mAdapter); } if (wrappers.mThumbnailAdapter != null && wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) { wrappers.mThumbnailAdapter.mCapturedFinishCallback - .onAnimationFinished(wrappers.mThumbnailAdapter); + .onAnimationFinished(wrappers.mAdapter.mAnimationType, + wrappers.mThumbnailAdapter); } mPendingAnimations.remove(i); } @@ -221,11 +224,13 @@ class RemoteAnimationController implements DeathRecipient { final RemoteAnimationRecord adapters = mPendingAnimations.get(i); if (adapters.mAdapter != null) { adapters.mAdapter.mCapturedFinishCallback - .onAnimationFinished(adapters.mAdapter); + .onAnimationFinished(adapters.mAdapter.mAnimationType, + adapters.mAdapter); } if (adapters.mThumbnailAdapter != null) { adapters.mThumbnailAdapter.mCapturedFinishCallback - .onAnimationFinished(adapters.mThumbnailAdapter); + .onAnimationFinished(adapters.mAdapter.mAnimationType, + adapters.mThumbnailAdapter); } mPendingAnimations.remove(i); ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s", @@ -234,7 +239,8 @@ class RemoteAnimationController implements DeathRecipient { for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) { final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i); - adapter.getLeashFinishedCallback().onAnimationFinished(adapter); + adapter.getLeashFinishedCallback().onAnimationFinished( + adapter.getLastAnimationType(), adapter); mPendingWallpaperAnimations.remove(i); ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken()); } @@ -393,6 +399,7 @@ class RemoteAnimationController implements DeathRecipient { private final RemoteAnimationRecord mRecord; SurfaceControl mCapturedLeash; private OnAnimationFinishedCallback mCapturedFinishCallback; + private @AnimationType int mAnimationType; final Point mPosition = new Point(); final Rect mStackBounds = new Rect(); @@ -410,7 +417,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, OnAnimationFinishedCallback finishCallback) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); // Restore z-layering, position and stack crop until client has a chance to modify it. @@ -425,6 +432,7 @@ class RemoteAnimationController implements DeathRecipient { } mCapturedLeash = animationLeash; mCapturedFinishCallback = finishCallback; + mAnimationType = type; } @Override diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index a13399bcb69c..2fdcbc9083f6 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -41,12 +40,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; -import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID; -import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT; -import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; -import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES; -import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY; -import static com.android.server.am.ActivityStackSupervisorProto.ROOT_WINDOW_CONTAINER; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; @@ -74,6 +67,9 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.RootWindowContainerProto.DISPLAYS; +import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; +import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; +import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES; import static com.android.server.wm.RootWindowContainerProto.WINDOWS; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; @@ -1278,7 +1274,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - public void dumpDebugInner(ProtoOutputStream proto, long fieldId, + @Override + public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { return; @@ -1290,14 +1287,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int count = mChildren.size(); for (int i = 0; i < count; ++i) { final DisplayContent displayContent = mChildren.get(i); - displayContent.dumpDebugInner(proto, DISPLAYS, logLevel); + displayContent.dumpDebug(proto, DISPLAYS, logLevel); } } if (logLevel == WindowTraceLogLevel.ALL) { forAllWindows((w) -> { - w.writeIdentifierToProto(proto, WINDOWS); + w.dumpDebug(proto, WINDOWS, logLevel); }, true); } + + mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER); + proto.write(IS_HOME_RECENTS_COMPONENT, + mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); + mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES); + proto.end(token); } @@ -3541,15 +3544,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - public void dumpDisplays(PrintWriter pw) { - for (int i = getChildCount() - 1; i >= 0; --i) { - final DisplayContent display = getChildAt(i); - pw.print("[id:" + display.mDisplayId + " stacks:"); - display.dumpStacks(pw); - pw.print("]"); - } - } - boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage) { boolean printed = false; @@ -3578,34 +3572,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return printed; } - @Override - public void dumpDebug(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { - final long token = proto.start(fieldId); - dumpDebugInner(proto, ROOT_WINDOW_CONTAINER, logLevel); - for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) { - final DisplayContent displayContent = getChildAt(displayNdx); - displayContent.dumpDebug(proto, - com.android.server.am.ActivityStackSupervisorProto.DISPLAYS, logLevel); - } - mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER); - // TODO(b/111541062): Update tests to look for resumed activities on all displays - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - if (focusedStack != null) { - proto.write(FOCUSED_STACK_ID, focusedStack.getRootTaskId()); - final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity(); - if (focusedActivity != null) { - focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); - } - } else { - proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); - } - proto.write(IS_HOME_RECENTS_COMPONENT, - mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); - mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES); - proto.end(token); - } - private final class SleepTokenImpl extends ActivityTaskManagerInternal.SleepToken { private final String mTag; private final long mAcquireTime; diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index e7aca898b19d..f6cdac5d4565 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -24,6 +24,7 @@ import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA; import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA; import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING; import static com.android.server.wm.ScreenRotationAnimationProto.STARTED; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; @@ -48,6 +49,8 @@ import android.view.animation.Transformation; import com.android.internal.R; import com.android.server.protolog.common.ProtoLog; +import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.RotationAnimationUtils; import java.io.PrintWriter; @@ -670,33 +673,35 @@ class ScreenRotationAnimation { * Start an animation defined by animationSpec on a new {@link SurfaceAnimator}. * * @param animatable The animatable used for the animation. - * @param animationSpec The spec of the animation. - * @param animationFinishedCallback Callback passed to the {@link SurfaceAnimator} and - * called when the animation finishes. + * @param animationSpec The spec of the animation. + * @param animationFinishedCallback Callback passed to the {@link SurfaceAnimator} + * and called when the animation finishes. * @return The newly created {@link SurfaceAnimator} that as been started. */ private SurfaceAnimator startAnimation( SurfaceAnimator.Animatable animatable, LocalAnimationAdapter.AnimationSpec animationSpec, - Runnable animationFinishedCallback) { + OnAnimationFinishedCallback animationFinishedCallback) { SurfaceAnimator animator = new SurfaceAnimator( animatable, animationFinishedCallback, mService); LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter( animationSpec, mService.mSurfaceAnimationRunner); animator.startAnimation(mDisplayContent.getPendingTransaction(), - localAnimationAdapter, false); + localAnimationAdapter, false, ANIMATION_TYPE_SCREEN_ROTATION); return animator; } - private void onAnimationEnd() { + private void onAnimationEnd(@AnimationType int type, AnimationAdapter anim) { synchronized (mService.mGlobalLock) { if (isAnimating()) { ProtoLog.v(WM_DEBUG_ORIENTATION, - "ScreenRotation sill animating: mDisplayAnimator: %s\n" - + "mEnterBlackFrameAnimator: " - + "%s\nmRotateScreenAnimator: %s\n" + "ScreenRotation still animating: type: %d\n" + + "mDisplayAnimator: %s\n" + + "mEnterBlackFrameAnimator: %s\n" + + "mRotateScreenAnimator: %s\n" + "mScreenshotRotationAnimator: %s", + type, mDisplayAnimator != null ? mDisplayAnimator.isAnimating() : null, mEnterBlackFrameAnimator != null diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index ab1f34adbeeb..9df42486580b 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -622,7 +622,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void grantInputChannel(int displayId, SurfaceControl surface, - IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { + IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) { if (hostInputToken == null && !mCanAddInternalSystemWindow) { // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to // embedded windows without providing a host window input token @@ -631,8 +631,19 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final long identity = Binder.clearCallingIdentity(); try { - mService.grantInputChannel(mUid, mPid, displayId, surface, window, - hostInputToken, outInputChannel); + mService.grantInputChannel(mUid, mPid, displayId, surface, window, hostInputToken, + flags, outInputChannel); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { + final long identity = Binder.clearCallingIdentity(); + try { + mService.updateInputChannel(channelToken, displayId, surface, flags); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index cb1676f3a7b1..7164cd85230b 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -23,6 +23,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.Slog; @@ -33,6 +34,8 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * A class that can run animations on objects that have a set of child surfaces. We do this by @@ -47,6 +50,7 @@ class SurfaceAnimator { private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM; private final WindowManagerService mService; private AnimationAdapter mAnimation; + private @AnimationType int mAnimationType; @VisibleForTesting SurfaceControl mLeash; @@ -55,30 +59,32 @@ class SurfaceAnimator { private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback; @VisibleForTesting @Nullable - final Runnable mStaticAnimationFinishedCallback; + final OnAnimationFinishedCallback mStaticAnimationFinishedCallback; @Nullable - private Runnable mAnimationFinishedCallback; + private OnAnimationFinishedCallback mAnimationFinishedCallback; private boolean mAnimationStartDelayed; /** * @param animatable The object to animate. - * @param animationFinishedCallback Callback to invoke when an animation has finished running. + * @param staticAnimationFinishedCallback Callback to invoke when an animation has finished + * running. */ - SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback, + SurfaceAnimator(Animatable animatable, + @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback, WindowManagerService service) { mAnimatable = animatable; mService = service; - mStaticAnimationFinishedCallback = animationFinishedCallback; - mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback); + mStaticAnimationFinishedCallback = staticAnimationFinishedCallback; + mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback); } private OnAnimationFinishedCallback getFinishedCallback( - @Nullable Runnable animationFinishedCallback) { - return anim -> { + @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) { + return (type, anim) -> { synchronized (mService.mGlobalLock) { final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim); if (target != null) { - target.mInnerAnimationFinishedCallback.onAnimationFinished(anim); + target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim); return; } @@ -91,13 +97,14 @@ class SurfaceAnimator { if (anim != mAnimation) { return; } - final Runnable animationFinishCallback = mAnimationFinishedCallback; + final OnAnimationFinishedCallback animationFinishCallback = + mAnimationFinishedCallback; reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */); - if (animationFinishedCallback != null) { - animationFinishedCallback.run(); + if (staticAnimationFinishedCallback != null) { + staticAnimationFinishedCallback.onAnimationFinished(type, anim); } if (animationFinishCallback != null) { - animationFinishCallback.run(); + animationFinishCallback.onAnimationFinished(type, anim); } }; if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) { @@ -120,9 +127,11 @@ class SurfaceAnimator { * @param animationFinishedCallback The callback being triggered when the animation finishes. */ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, - @Nullable Runnable animationFinishedCallback) { + @AnimationType int type, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { cancelAnimation(t, true /* restarting */, true /* forwardCancel */); mAnimation = anim; + mAnimationType = type; mAnimationFinishedCallback = animationFinishedCallback; final SurfaceControl surface = mAnimatable.getSurfaceControl(); if (surface == null) { @@ -137,11 +146,12 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed"); return; } - mAnimation.startAnimation(mLeash, t, mInnerAnimationFinishedCallback); + mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback); } - void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) { - startAnimation(t, anim, hidden, null /* animationFinishedCallback */); + void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, + @AnimationType int type) { + startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */); } /** @@ -165,7 +175,7 @@ class SurfaceAnimator { mAnimationStartDelayed = false; if (delayed && mAnimation != null) { mAnimation.startAnimation(mLeash, mAnimatable.getPendingTransaction(), - mInnerAnimationFinishedCallback); + mAnimationType, mInnerAnimationFinishedCallback); mAnimatable.commitPendingTransaction(); } } @@ -245,6 +255,7 @@ class SurfaceAnimator { cancelAnimation(t, true /* restarting */, true /* forwardCancel */); mLeash = from.mLeash; mAnimation = from.mAnimation; + mAnimationType = from.mAnimationType; mAnimationFinishedCallback = from.mAnimationFinishedCallback; // Cancel source animation, but don't let animation runner cancel the animation. @@ -272,7 +283,8 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting); final SurfaceControl leash = mLeash; final AnimationAdapter animation = mAnimation; - final Runnable animationFinishedCallback = mAnimationFinishedCallback; + final @AnimationType int animationType = mAnimationType; + final OnAnimationFinishedCallback animationFinishedCallback = mAnimationFinishedCallback; reset(t, false); if (animation != null) { if (!mAnimationStartDelayed && forwardCancel) { @@ -280,10 +292,10 @@ class SurfaceAnimator { } if (!restarting) { if (mStaticAnimationFinishedCallback != null) { - mStaticAnimationFinishedCallback.run(); + mStaticAnimationFinishedCallback.onAnimationFinished(animationType, animation); } if (animationFinishedCallback != null) { - animationFinishedCallback.run(); + animationFinishedCallback.onAnimationFinished(animationType, animation); } } } @@ -325,6 +337,7 @@ class SurfaceAnimator { mLeash = null; mAnimation = null; mAnimationFinishedCallback = null; + mAnimationType = ANIMATION_TYPE_NONE; if (reparent) { // Make sure to inform the animatable after the surface was reparented (or reparent @@ -392,12 +405,72 @@ class SurfaceAnimator { } } + + /** + * No animation is specified. + * @hide + */ + static final int ANIMATION_TYPE_NONE = 0; + + /** + * Animation for an app transition. + * @hide + */ + static final int ANIMATION_TYPE_APP_TRANSITION = 1; + + /** + * Animation for screen rotation. + * @hide + */ + static final int ANIMATION_TYPE_SCREEN_ROTATION = 2; + + /** + * Animation for dimming. + * @hide + */ + static final int ANIMATION_TYPE_DIMMER = 3; + + /** + * Animation for recent apps. + * @hide + */ + static final int ANIMATION_TYPE_RECENTS = 4; + + /** + * Animation for a {@link WindowState} without animating the activity. + * @hide + */ + static final int ANIMATION_TYPE_WINDOW_ANIMATION = 5; + + /** + * Animation to control insets. This is actually not an animation, but is used to give the + * client a leash over the system window causing insets. + * @hide + */ + static final int ANIMATION_TYPE_INSETS_CONTROL = 6; + + /** + * The type of the animation. + * @hide + */ + @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = { + ANIMATION_TYPE_NONE, + ANIMATION_TYPE_APP_TRANSITION, + ANIMATION_TYPE_SCREEN_ROTATION, + ANIMATION_TYPE_DIMMER, + ANIMATION_TYPE_RECENTS, + ANIMATION_TYPE_WINDOW_ANIMATION, + ANIMATION_TYPE_INSETS_CONTROL + }) + @Retention(RetentionPolicy.SOURCE) + @interface AnimationType {} + /** * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the * component that is running the animation when the animation is finished. */ interface OnAnimationFinishedCallback { - void onAnimationFinished(AnimationAdapter anim); + void onAnimationFinished(@AnimationType int type, AnimationAdapter anim); } /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 28dc2a42da2a..87c91ef6b96c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -61,17 +61,6 @@ import static android.view.SurfaceControl.METADATA_TASK_ID; import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; -import static com.android.server.am.TaskRecordProto.ACTIVITIES; -import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; -import static com.android.server.am.TaskRecordProto.FULLSCREEN; -import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; -import static com.android.server.am.TaskRecordProto.MIN_HEIGHT; -import static com.android.server.am.TaskRecordProto.MIN_WIDTH; -import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY; -import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY; -import static com.android.server.am.TaskRecordProto.RESIZE_MODE; -import static com.android.server.am.TaskRecordProto.STACK_ID; -import static com.android.server.am.TaskRecordProto.TASK; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -90,7 +79,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.TaskProto.ACTIVITY; import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS; import static com.android.server.wm.TaskProto.FILLS_PARENT; import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; @@ -3160,29 +3148,6 @@ class Task extends WindowContainer<WindowContainer> { } } - // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged. - void dumpDebugInnerTaskOnly(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { - if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { - return; - } - - final long token = proto.start(fieldId); - super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); - proto.write(TaskProto.ID, mTaskId); - forAllActivities((r) -> { - r.dumpDebug(proto, ACTIVITY); - }); - proto.write(FILLS_PARENT, matchParentBounds()); - getBounds().dumpDebug(proto, TaskProto.BOUNDS); - mOverrideDisplayedBounds.dumpDebug(proto, DISPLAYED_BOUNDS); - if (mSurfaceControl != null) { - proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); - proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); - } - proto.end(token); - } - @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); @@ -3395,43 +3360,6 @@ class Task extends WindowContainer<WindowContainer> { return toString(); } - void dumpDebugInner(ProtoOutputStream proto, long fieldId, - @WindowTraceLogLevel int logLevel) { - if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { - return; - } - - final long token = proto.start(fieldId); - dumpDebugInnerTaskOnly(proto, TASK, logLevel); - proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId); - - forAllActivities((r) -> { - r.dumpDebug(proto, ACTIVITIES); - }); - proto.write(STACK_ID, getRootTaskId()); - if (mLastNonFullscreenBounds != null) { - mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); - } - if (realActivity != null) { - proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); - } - if (origActivity != null) { - proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); - } - proto.write(ACTIVITY_TYPE, getActivityType()); - proto.write(RESIZE_MODE, mResizeMode); - // TODO: Remove, no longer needed with windowingMode. - proto.write(FULLSCREEN, matchParentBounds()); - - if (!matchParentBounds()) { - final Rect bounds = getRequestedOverrideBounds(); - bounds.dumpDebug(proto, com.android.server.am.TaskRecordProto.BOUNDS); - } - proto.write(MIN_WIDTH, mMinWidth); - proto.write(MIN_HEIGHT, mMinHeight); - proto.end(token); - } - /** @see #getNumRunningActivities(TaskActivitiesReport) */ static class TaskActivitiesReport implements Consumer<ActivityRecord> { int numRunning; diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java index 801e5217098f..bd705998f49a 100644 --- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import android.graphics.Point; import android.os.SystemClock; @@ -26,6 +27,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import com.android.server.protolog.common.ProtoLog; +import com.android.server.wm.SurfaceAnimator.AnimationType; import java.io.PrintWriter; import java.util.ArrayList; @@ -40,6 +42,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter { private final WallpaperWindowToken mWallpaperToken; private SurfaceControl mCapturedLeash; private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback; + private @AnimationType int mLastAnimationType; private long mDurationHint; private long mStatusBarTransitionDelay; @@ -77,7 +80,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter { wallpaperWindow, durationHint, statusBarTransitionDelay, animationCanceledRunnable); wallpaperWindow.startAnimation(wallpaperWindow.getPendingTransaction(), - wallpaperAdapter, false /* hidden */); + wallpaperAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION); targets.add(wallpaperAdapter.createRemoteAnimationTarget()); adaptersOut.add(wallpaperAdapter); }); @@ -110,6 +113,13 @@ class WallpaperAnimationAdapter implements AnimationAdapter { } /** + * @return the type of animation. + */ + @AnimationType int getLastAnimationType() { + return mLastAnimationType; + } + + /** * @return the wallpaper window */ WallpaperWindowToken getToken() { @@ -124,13 +134,14 @@ class WallpaperAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, - SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); // Restore z-layering until client has a chance to modify it. t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex()); mCapturedLeash = animationLeash; mCapturedLeashFinishCallback = finishCallback; + mLastAnimationType = type; } @Override diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index d828ca6d7a96..86723153c5f6 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -31,6 +31,7 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_W import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -74,6 +75,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; +import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -1851,19 +1854,24 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @param anim The animation to run. * @param hidden Whether our container is currently hidden. TODO This should use isVisible at * some point but the meaning is too weird to work for all containers. + * @param type The type of animation defined as {@link AnimationType}. * @param animationFinishedCallback The callback being triggered when the animation finishes. */ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, - @Nullable Runnable animationFinishedCallback) { - if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim); + @AnimationType int type, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + if (DEBUG_ANIM) { + Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim); + } // TODO: This should use isVisible() but because isVisible has a really weird meaning at // the moment this doesn't work for all animatable window containers. - mSurfaceAnimator.startAnimation(t, anim, hidden, animationFinishedCallback); + mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback); } - void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) { - startAnimation(t, anim, hidden, null /* animationFinishedCallback */); + void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, + @AnimationType int type) { + startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */); } void transferAnimation(WindowContainer from) { @@ -1916,7 +1924,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @see #getAnimationAdapter */ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction, @Nullable Runnable animationFinishedCallback) { + boolean isVoiceInteraction, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { if (mWmService.mDisableTransitionAnimation) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: transition animation is disabled or skipped. " @@ -1937,7 +1946,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< AnimationAdapter thumbnailAdapter = adapters.second; if (adapter != null) { startAnimation(getPendingTransaction(), adapter, !isVisible(), - animationFinishedCallback); + ANIMATION_TYPE_APP_TRANSITION, animationFinishedCallback); if (adapter.getShowWallpaper()) { getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } @@ -2128,7 +2137,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< /** * Called when an animation has finished running. */ - protected void onAnimationFinished() { + protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { mWmService.onAnimationFinished(); } diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java index 8948f6fc2ab1..90e3be74c743 100644 --- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java +++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java @@ -20,6 +20,7 @@ import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT; import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR; import static com.android.server.wm.WindowContainerThumbnailProto.WIDTH; @@ -40,6 +41,7 @@ import android.view.animation.Animation; import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; +import com.android.server.wm.SurfaceAnimator.AnimationType; import java.util.function.Supplier; @@ -85,7 +87,7 @@ class WindowContainerThumbnail implements Animatable { // We can't use a delegating constructor since we need to // reference this::onAnimationFinished mSurfaceAnimator = - new SurfaceAnimator(this, null /* animationFinishedCallback */, + new SurfaceAnimator(this, this::onAnimationFinished /* animationFinishedCallback */, container.mWmService); } mWidth = thumbnailHeader.getWidth(); @@ -130,14 +132,19 @@ class WindowContainerThumbnail implements Animatable { new WindowAnimationSpec(anim, position, mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(), mWindowContainer.getDisplayContent().getWindowCornerRadius()), - mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */); + mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */, + ANIMATION_TYPE_RECENTS, null /* animationFinishedCallback */); } /** * Start animation with existing adapter. */ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) { - mSurfaceAnimator.startAnimation(t, anim, hidden); + mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS, + null /* animationFinishedCallback */); + } + + private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { } void setShowing(Transaction pendingTransaction, boolean show) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2ee5faf9f730..a5b99b0a26a3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -397,7 +397,7 @@ public class WindowManagerService extends IWindowManager.Stub * @see #HIERARCHICAL_ANIMATIONS_PROPERTY */ static boolean sHierarchicalAnimations = - SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, false); + SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, true); // Enums for animation scale update types. @Retention(RetentionPolicy.SOURCE) @@ -5912,7 +5912,7 @@ public class WindowManagerService extends IWindowManager.Stub */ void dumpDebugLocked(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) { mPolicy.dumpDebug(proto, POLICY); - mRoot.dumpDebugInner(proto, ROOT_WINDOW_CONTAINER, logLevel); + mRoot.dumpDebug(proto, ROOT_WINDOW_CONTAINER, logLevel); final DisplayContent topFocusedDisplayContent = mRoot.getTopFocusedDisplayContent(); if (topFocusedDisplayContent.mCurrentFocus != null) { topFocusedDisplayContent.mCurrentFocus.writeIdentifierToProto(proto, FOCUSED_WINDOW); @@ -7814,40 +7814,52 @@ public class WindowManagerService extends IWindowManager.Stub * views. */ void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface, - IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { - InputApplicationHandle applicationHandle = null; + IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) { + final InputApplicationHandle applicationHandle; final String name; final InputChannel[] inputChannels; final InputChannel clientChannel; final InputChannel serverChannel; synchronized (mGlobalLock) { - final WindowState hostWindow = mInputToWindowMap.get(hostInputToken); - final String hostWindowName = (hostWindow != null) - ? hostWindow.getWindowTag().toString() : "Internal"; - name = "EmbeddedWindow{ u" + UserHandle.getUserId(callingUid) - + " " + hostWindowName + "}"; + EmbeddedWindowController.EmbeddedWindow win = + new EmbeddedWindowController.EmbeddedWindow(window, + mInputToWindowMap.get(hostInputToken), callingUid, callingPid); + name = win.getName(); inputChannels = InputChannel.openInputChannelPair(name); serverChannel = inputChannels[0]; clientChannel = inputChannels[1]; mInputManager.registerInputChannel(serverChannel); - mEmbeddedWindowController.add(serverChannel.getToken(), window, hostWindow, callingUid, - callingPid); - - if (hostWindow != null - && hostWindow.mInputWindowHandle.inputApplicationHandle != null) { - applicationHandle = new InputApplicationHandle( - hostWindow.mInputWindowHandle.inputApplicationHandle); + mEmbeddedWindowController.add(clientChannel.getToken(), win); + if (serverChannel.getToken() != clientChannel.getToken()) { + throw new IllegalStateException("Client and Server channel are expected to" + + "be the same"); } + + applicationHandle = win.getApplicationHandle(); } + updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface, + name, applicationHandle, flags); + clientChannel.transferTo(outInputChannel); clientChannel.dispose(); + // Prevent the java finalizer from breaking the input channel. But we won't + // do any further management so we just release the java ref and let the + // InputDispatcher hold the last ref. + serverChannel.release(); + } + private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid, + int displayId, SurfaceControl surface, String name, + InputApplicationHandle applicationHandle, int flags) { InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId); - h.token = serverChannel.getToken(); + h.token = channelToken; h.name = name; - h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + + final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE + | LayoutParams.FLAG_SLIPPERY); + h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags; h.layoutParamsType = 0; h.dispatchingTimeoutNanos = -1; h.canReceiveKeys = false; @@ -7862,15 +7874,34 @@ public class WindowManagerService extends IWindowManager.Stub h.replaceTouchableRegionWithCrop(null); - SurfaceSession s = new SurfaceSession(); SurfaceControl.Transaction t = mTransactionFactory.get(); t.setInputWindowInfo(surface, h); t.apply(); + t.close(); + } - // Prevent the java finalizer from breaking the input channel. But we won't - // do any further management so we just release the java ref and let the - // InputDispatcher hold the last ref. - serverChannel.release(); + /** + * Updates the flags on an existing surface's input channel. This assumes the surface provided + * is the one associated with the provided input-channel. If this isn't the case, behavior + * is undefined. + */ + void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { + final InputApplicationHandle applicationHandle; + final String name; + final EmbeddedWindowController.EmbeddedWindow win; + synchronized (mGlobalLock) { + win = mEmbeddedWindowController.get(channelToken); + if (win == null) { + Slog.e(TAG, "Couldn't find window for provided channelToken."); + return; + } + name = win.getName(); + applicationHandle = win.getApplicationHandle(); + } + + updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name, + applicationHandle, flags); } /** Return whether layer tracing is enabled */ diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index fc04126714d1..42e5bbc1c1ee 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -115,6 +115,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; @@ -231,6 +232,7 @@ import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.utils.WmDisplayCutout; import java.io.PrintWriter; @@ -415,6 +417,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private final WindowFrames mWindowFrames = new WindowFrames(); + /** The frames used to compute a temporal layout appearance. */ + private WindowFrames mSimulatedWindowFrames; + /** * Usually empty. Set to the task's tempInsetFrame. See *{@link android.app.IActivityTaskManager#resizeDockedStack}. @@ -970,6 +975,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return super.getDisplayedBounds(); } + void computeFrame(DisplayFrames displayFrames) { + getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); + computeFrameLw(); + // Update the source frame to provide insets to other windows during layout. If the + // simulated frames exist, then this is not computing a stable result so just skip. + if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) { + mControllableInsetProvider.updateSourceFrame(); + } + } + @Override public void computeFrameLw() { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { @@ -985,6 +1000,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds(); final boolean windowsAreFloating = task != null && task.isFloating(); final DisplayContent dc = getDisplayContent(); + final WindowFrames windowFrames = getLayoutingWindowFrames(); mInsetFrame.set(getBounds()); @@ -1006,43 +1022,43 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget; if (isFullscreenAndFillsDisplay || layoutInParentFrame()) { // We use the parent frame as the containing frame for fullscreen and child windows - mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame); - layoutDisplayFrame = mWindowFrames.mDisplayFrame; - layoutContainingFrame = mWindowFrames.mParentFrame; + windowFrames.mContainingFrame.set(windowFrames.mParentFrame); + layoutDisplayFrame = windowFrames.mDisplayFrame; + layoutContainingFrame = windowFrames.mParentFrame; layoutXDiff = 0; layoutYDiff = 0; } else { - mWindowFrames.mContainingFrame.set(getDisplayedBounds()); + windowFrames.mContainingFrame.set(getDisplayedBounds()); if (mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) { // If the bounds are frozen, we still want to translate the window freely and only // freeze the size. Rect frozen = mActivityRecord.mFrozenBounds.peek(); - mWindowFrames.mContainingFrame.right = - mWindowFrames.mContainingFrame.left + frozen.width(); - mWindowFrames.mContainingFrame.bottom = - mWindowFrames.mContainingFrame.top + frozen.height(); + windowFrames.mContainingFrame.right = + windowFrames.mContainingFrame.left + frozen.width(); + windowFrames.mContainingFrame.bottom = + windowFrames.mContainingFrame.top + frozen.height(); } // IME is up and obscuring this window. Adjust the window position so it is visible. if (isImeTarget) { if (inFreeformWindowingMode()) { // Push the freeform window up to make room for the IME. However, don't push // it up past the top of the screen. - final int bottomOverlap = mWindowFrames.mContainingFrame.bottom - - mWindowFrames.mVisibleFrame.bottom; + final int bottomOverlap = windowFrames.mContainingFrame.bottom + - windowFrames.mVisibleFrame.bottom; if (bottomOverlap > 0) { - final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top - - mWindowFrames.mContentFrame.top, 0); + final int distanceToTop = Math.max(windowFrames.mContainingFrame.top + - windowFrames.mContentFrame.top, 0); int offs = Math.min(bottomOverlap, distanceToTop); - mWindowFrames.mContainingFrame.offset(0, -offs); + windowFrames.mContainingFrame.offset(0, -offs); mInsetFrame.offset(0, -offs); } - } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom - > mWindowFrames.mParentFrame.bottom) { + } else if (!inPinnedWindowingMode() && windowFrames.mContainingFrame.bottom + > windowFrames.mParentFrame.bottom) { // But in docked we want to behave like fullscreen and behave as if the task // were given smaller bounds for the purposes of layout. Skip adjustments for // the pinned stack, they are handled separately in the PinnedStackController. - mWindowFrames.mContainingFrame.bottom = mWindowFrames.mParentFrame.bottom; + windowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom; } } @@ -1050,8 +1066,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // In floating modes (e.g. freeform, pinned) we have only to set the rectangle // if it wasn't set already. No need to intersect it with the (visible) // "content frame" since it is allowed to be outside the visible desktop. - if (mWindowFrames.mContainingFrame.isEmpty()) { - mWindowFrames.mContainingFrame.set(mWindowFrames.mContentFrame); + if (windowFrames.mContainingFrame.isEmpty()) { + windowFrames.mContainingFrame.set(windowFrames.mContentFrame); } } @@ -1061,115 +1077,115 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // PIP edge case: When going from pinned to fullscreen, we apply a // tempInsetFrame for the full task - but we're still at the start of the animation. // To prevent a jump if there's a letterbox, restrict to the parent frame. - mInsetFrame.intersectUnchecked(mWindowFrames.mParentFrame); - mWindowFrames.mContainingFrame.intersectUnchecked(mWindowFrames.mParentFrame); + mInsetFrame.intersectUnchecked(windowFrames.mParentFrame); + windowFrames.mContainingFrame.intersectUnchecked(windowFrames.mParentFrame); } - layoutDisplayFrame = new Rect(mWindowFrames.mDisplayFrame); - mWindowFrames.mDisplayFrame.set(mWindowFrames.mContainingFrame); - layoutXDiff = mInsetFrame.left - mWindowFrames.mContainingFrame.left; - layoutYDiff = mInsetFrame.top - mWindowFrames.mContainingFrame.top; + layoutDisplayFrame = new Rect(windowFrames.mDisplayFrame); + windowFrames.mDisplayFrame.set(windowFrames.mContainingFrame); + layoutXDiff = mInsetFrame.left - windowFrames.mContainingFrame.left; + layoutYDiff = mInsetFrame.top - windowFrames.mContainingFrame.top; layoutContainingFrame = mInsetFrame; mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight); - subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame, + subtractInsets(windowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame, mTmpRect); if (!layoutInParentFrame()) { - subtractInsets(mWindowFrames.mContainingFrame, layoutContainingFrame, - mWindowFrames.mParentFrame, mTmpRect); - subtractInsets(mInsetFrame, layoutContainingFrame, mWindowFrames.mParentFrame, + subtractInsets(windowFrames.mContainingFrame, layoutContainingFrame, + windowFrames.mParentFrame, mTmpRect); + subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame, mTmpRect); } layoutDisplayFrame.intersect(layoutContainingFrame); } - final int pw = mWindowFrames.mContainingFrame.width(); - final int ph = mWindowFrames.mContainingFrame.height(); + final int pw = windowFrames.mContainingFrame.width(); + final int ph = windowFrames.mContainingFrame.height(); if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { mLastRequestedWidth = mRequestedWidth; mLastRequestedHeight = mRequestedHeight; - mWindowFrames.setContentChanged(true); + windowFrames.setContentChanged(true); } - final int fw = mWindowFrames.mFrame.width(); - final int fh = mWindowFrames.mFrame.height(); + final int fw = windowFrames.mFrame.width(); + final int fh = windowFrames.mFrame.height(); - applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame); + applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame); // Make sure the content and visible frames are inside of the // final window frame. - if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) { - final int visBottom = mWindowFrames.mVisibleFrame.bottom; - final int contentBottom = mWindowFrames.mContentFrame.bottom; - mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); - mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame); - mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame); + if (windowsAreFloating && !windowFrames.mFrame.isEmpty()) { + final int visBottom = windowFrames.mVisibleFrame.bottom; + final int contentBottom = windowFrames.mContentFrame.bottom; + windowFrames.mContentFrame.set(windowFrames.mFrame); + windowFrames.mVisibleFrame.set(windowFrames.mContentFrame); + windowFrames.mStableFrame.set(windowFrames.mContentFrame); if (isImeTarget && inFreeformWindowingMode()) { // After displacing a freeform window to make room for the ime, any part of // the window still covered by IME should be inset. - if (contentBottom + layoutYDiff < mWindowFrames.mContentFrame.bottom) { - mWindowFrames.mContentFrame.bottom = contentBottom + layoutYDiff; + if (contentBottom + layoutYDiff < windowFrames.mContentFrame.bottom) { + windowFrames.mContentFrame.bottom = contentBottom + layoutYDiff; } - if (visBottom + layoutYDiff < mWindowFrames.mVisibleFrame.bottom) { - mWindowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff; + if (visBottom + layoutYDiff < windowFrames.mVisibleFrame.bottom) { + windowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff; } } } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { - dc.getDockedDividerController().positionDockedStackedDivider(mWindowFrames.mFrame); - mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); - if (!mWindowFrames.mFrame.equals(mWindowFrames.mLastFrame)) { + dc.getDockedDividerController().positionDockedStackedDivider(windowFrames.mFrame); + windowFrames.mContentFrame.set(windowFrames.mFrame); + if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) { mMovedByResize = true; } } else { - mWindowFrames.mContentFrame.set( - Math.max(mWindowFrames.mContentFrame.left, mWindowFrames.mFrame.left), - Math.max(mWindowFrames.mContentFrame.top, mWindowFrames.mFrame.top), - Math.min(mWindowFrames.mContentFrame.right, mWindowFrames.mFrame.right), - Math.min(mWindowFrames.mContentFrame.bottom, mWindowFrames.mFrame.bottom)); + windowFrames.mContentFrame.set( + Math.max(windowFrames.mContentFrame.left, windowFrames.mFrame.left), + Math.max(windowFrames.mContentFrame.top, windowFrames.mFrame.top), + Math.min(windowFrames.mContentFrame.right, windowFrames.mFrame.right), + Math.min(windowFrames.mContentFrame.bottom, windowFrames.mFrame.bottom)); - mWindowFrames.mVisibleFrame.set( - Math.max(mWindowFrames.mVisibleFrame.left, mWindowFrames.mFrame.left), - Math.max(mWindowFrames.mVisibleFrame.top, mWindowFrames.mFrame.top), - Math.min(mWindowFrames.mVisibleFrame.right, mWindowFrames.mFrame.right), - Math.min(mWindowFrames.mVisibleFrame.bottom, mWindowFrames.mFrame.bottom)); + windowFrames.mVisibleFrame.set( + Math.max(windowFrames.mVisibleFrame.left, windowFrames.mFrame.left), + Math.max(windowFrames.mVisibleFrame.top, windowFrames.mFrame.top), + Math.min(windowFrames.mVisibleFrame.right, windowFrames.mFrame.right), + Math.min(windowFrames.mVisibleFrame.bottom, windowFrames.mFrame.bottom)); - mWindowFrames.mStableFrame.set( - Math.max(mWindowFrames.mStableFrame.left, mWindowFrames.mFrame.left), - Math.max(mWindowFrames.mStableFrame.top, mWindowFrames.mFrame.top), - Math.min(mWindowFrames.mStableFrame.right, mWindowFrames.mFrame.right), - Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom)); + windowFrames.mStableFrame.set( + Math.max(windowFrames.mStableFrame.left, windowFrames.mFrame.left), + Math.max(windowFrames.mStableFrame.top, windowFrames.mFrame.top), + Math.min(windowFrames.mStableFrame.right, windowFrames.mFrame.right), + Math.min(windowFrames.mStableFrame.bottom, windowFrames.mFrame.bottom)); } if (mAttrs.type == TYPE_DOCK_DIVIDER) { - final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo( - mWindowFrames.mDisplayFrame); - mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets()); + final WmDisplayCutout c = windowFrames.mDisplayCutout.calculateRelativeTo( + windowFrames.mDisplayFrame); + windowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets()); } else { getDisplayContent().getBounds(mTmpRect); - mWindowFrames.calculateInsets( + windowFrames.calculateInsets( windowsAreFloating, isFullscreenAndFillsDisplay, mTmpRect); } - mWindowFrames.setDisplayCutout( - mWindowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame)); + windowFrames.setDisplayCutout( + windowFrames.mDisplayCutout.calculateRelativeTo(windowFrames.mFrame)); // Offset the actual frame by the amount layout frame is off. - mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); + windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff); - mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); + windowFrames.mCompatFrame.set(windowFrames.mFrame); if (inSizeCompatMode()) { // If there is a size compatibility scale being applied to the // window, we need to apply this to its insets so that they are // reported to the app in its coordinate space. - mWindowFrames.scaleInsets(mInvGlobalScale); + windowFrames.scaleInsets(mInvGlobalScale); // Also the scaled frame that we report to the app needs to be // adjusted to be in its coordinate space. - mWindowFrames.mCompatFrame.scale(mInvGlobalScale); + windowFrames.mCompatFrame.scale(mInvGlobalScale); } - if (mIsWallpaper && (fw != mWindowFrames.mFrame.width() - || fh != mWindowFrames.mFrame.height())) { + if (mIsWallpaper && (fw != windowFrames.mFrame.width() + || fh != windowFrames.mFrame.height())) { final DisplayContent displayContent = getDisplayContent(); if (displayContent != null) { final DisplayInfo displayInfo = displayContent.getDisplayInfo(); @@ -1179,7 +1195,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } // Calculate relative frame - mWindowFrames.mRelFrame.set(mWindowFrames.mFrame); + windowFrames.mRelFrame.set(windowFrames.mFrame); WindowContainer parent = getParent(); int parentLeft = 0; int parentTop = 0; @@ -1191,15 +1207,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP parentLeft = parentBounds.left; parentTop = parentBounds.top; } - mWindowFrames.mRelFrame.offsetTo(mWindowFrames.mFrame.left - parentLeft, - mWindowFrames.mFrame.top - parentTop); + windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft, + windowFrames.mFrame.top - parentTop); if (DEBUG_LAYOUT || DEBUG) { Slog.v(TAG, "Resolving (mRequestedWidth=" + mRequestedWidth + ", mRequestedheight=" + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph - + "): frame=" + mWindowFrames.mFrame.toShortString() - + " " + mWindowFrames.getInsetsInfo() + + "): frame=" + windowFrames.mFrame.toShortString() + + " " + windowFrames.getInsetsInfo() + " " + mAttrs.getTitle()); } } @@ -3984,7 +4000,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - private void applyGravityAndUpdateFrame(Rect containingFrame, Rect displayFrame) { + private void applyGravityAndUpdateFrame(WindowFrames windowFrames, Rect containingFrame, + Rect displayFrame) { final int pw = containingFrame.width(); final int ph = containingFrame.height(); final Task task = getTask(); @@ -4054,19 +4071,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Set mFrame Gravity.apply(mAttrs.gravity, w, h, containingFrame, (int) (x + mAttrs.horizontalMargin * pw), - (int) (y + mAttrs.verticalMargin * ph), mWindowFrames.mFrame); + (int) (y + mAttrs.verticalMargin * ph), windowFrames.mFrame); // Now make sure the window fits in the overall display frame. if (fitToDisplay) { - Gravity.applyDisplay(mAttrs.gravity, displayFrame, mWindowFrames.mFrame); + Gravity.applyDisplay(mAttrs.gravity, displayFrame, windowFrames.mFrame); } // We need to make sure we update the CompatFrame as it is used for // cropping decisions, etc, on systems where we lack a decor layer. - mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame); + windowFrames.mCompatFrame.set(windowFrames.mFrame); if (inSizeCompatMode) { // See comparable block in computeFrameLw. - mWindowFrames.mCompatFrame.scale(mInvGlobalScale); + windowFrames.mCompatFrame.scale(mInvGlobalScale); } } @@ -5027,12 +5044,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } private void startAnimation(Transaction t, AnimationAdapter adapter) { - startAnimation(t, adapter, mWinAnimator.mLastHidden, null /* animationFinishedCallback */); + startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION, + null /* animationFinishedCallback */); } @Override - protected void onAnimationFinished() { - super.onAnimationFinished(); + protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { + super.onAnimationFinished(type, anim); mWinAnimator.onAnimationFinished(); } @@ -5530,6 +5548,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mWindowFrames; } + /** + * If the transient frame is set, the computed result won't be used in real layout. So this + * frames must be cleared when the simulated computation is done. + */ + void setSimulatedWindowFrames(WindowFrames windowFrames) { + mSimulatedWindowFrames = windowFrames; + } + + /** + * Use this method only when the simulated frames may be set, so it is clearer that the calling + * path may be used to simulate layout. + */ + WindowFrames getLayoutingWindowFrames() { + return mSimulatedWindowFrames != null ? mSimulatedWindowFrames : mWindowFrames; + } + void resetContentChanged() { mWindowFrames.setContentChanged(false); } diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 12de20cc3d51..1a8f1f9f0024 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1218,19 +1218,21 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement SET(BasebandCn0DbHz, measurement_V2_1->basebandCN0DbHz); if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) { - SET(ReceiverInterSignalBiasNs, measurement_V2_1->receiverInterSignalBiasNs); + SET(ReceiverInterSignalBiasNanos, measurement_V2_1->receiverInterSignalBiasNs); } if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) { - SET(ReceiverInterSignalBiasUncertaintyNs, measurement_V2_1->receiverInterSignalBiasUncertaintyNs); + SET(ReceiverInterSignalBiasUncertaintyNanos, + measurement_V2_1->receiverInterSignalBiasUncertaintyNs); } if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) { - SET(SatelliteInterSignalBiasNs, measurement_V2_1->satelliteInterSignalBiasNs); + SET(SatelliteInterSignalBiasNanos, measurement_V2_1->satelliteInterSignalBiasNs); } if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) { - SET(SatelliteInterSignalBiasUncertaintyNs, measurement_V2_1->satelliteInterSignalBiasUncertaintyNs); + SET(SatelliteInterSignalBiasUncertaintyNanos, + measurement_V2_1->satelliteInterSignalBiasUncertaintyNs); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ec3ef7807c3a..65cabadaa3d8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -15077,9 +15077,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return packages; } - private List<String> getDefaultCrossProfilePackages() { - return Arrays.asList(mContext.getResources() + @Override + public List<String> getDefaultCrossProfilePackages() { + Set<String> crossProfilePackages = new HashSet<>(); + + Collections.addAll(crossProfilePackages, mContext.getResources() .getStringArray(R.array.cross_profile_apps)); + Collections.addAll(crossProfilePackages, mContext.getResources() + .getStringArray(R.array.vendor_cross_profile_apps)); + + return new ArrayList<>(crossProfilePackages); } private List<ActiveAdmin> getProfileOwnerAdminsForCurrentProfileGroup() { diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index f1b637f516ea..91d05723a605 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -111,10 +111,9 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path, binder::Status BinderIncrementalService::createStorage(const std::string& path, const DataLoaderParamsParcel& params, int32_t createMode, int32_t* _aidl_return) { - *_aidl_return = - mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), - android::incremental::IncrementalService::CreateOptions( - createMode)); + *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), + android::incremental::IncrementalService::CreateOptions( + createMode)); return ok(); } @@ -195,7 +194,7 @@ binder::Status BinderIncrementalService::makeFile( return ok(); } - *_aidl_return = mImpl.makeFile(storageId, path, 0555, fileId, nfp); + *_aidl_return = mImpl.makeFile(storageId, path, 0777, fileId, nfp); return ok(); } binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId, diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 414c66c866db..e4a37dde7758 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -30,7 +30,6 @@ #include <binder/BinderService.h> #include <binder/ParcelFileDescriptor.h> #include <binder/Status.h> - #include <openssl/sha.h> #include <sys/stat.h> #include <uuid/uuid.h> @@ -612,13 +611,18 @@ int IncrementalService::bind(StorageId storage, std::string_view source, std::st if (!ifs) { return -EINVAL; } - auto normSource = path::normalize(source); std::unique_lock l(ifs->lock); const auto storageInfo = ifs->storages.find(storage); if (storageInfo == ifs->storages.end()) { return -EINVAL; } + std::string normSource; + if (path::isAbsolute(source)) { + normSource = path::normalize(source); + } else { + normSource = path::normalize(path::join(storageInfo->second.name, source)); + } if (!path::startsWith(normSource, storageInfo->second.name)) { return -EINVAL; } @@ -673,7 +677,20 @@ int IncrementalService::unbind(StorageId storage, std::string_view target) { int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id, incfs::NewFileParams params) { if (auto ifs = getIfs(storage)) { - auto err = mIncFs->makeFile(ifs->control, path, mode, id, params); + const auto storageInfo = ifs->storages.find(storage); + if (storageInfo == ifs->storages.end()) { + return -EINVAL; + } + std::string normPath; + if (path::isAbsolute(path)) { + normPath = path::normalize(path); + } else { + normPath = path::normalize(path::join(storageInfo->second.name, path)); + } + if (!path::startsWith(normPath, storageInfo->second.name)) { + return -EINVAL; + } + auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); if (err) { return err; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 6ba4330f3916..036335ca9011 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -71,7 +71,6 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; -import android.util.StatsLog; import android.view.contentcapture.ContentCaptureManager; import com.android.internal.R; @@ -79,6 +78,7 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BinderInternal; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.EmergencyAffordanceManager; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.ILockSettings; import com.android.server.am.ActivityManagerService; import com.android.server.appbinding.AppBindingService; @@ -453,8 +453,9 @@ public final class SystemServer { final long uptimeMillis = SystemClock.elapsedRealtime(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis); if (!mRuntimeRestart) { - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, - StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + FrameworkStatsLog + .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START, uptimeMillis); } @@ -570,8 +571,8 @@ public final class SystemServer { if (!mRuntimeRestart && !isFirstBootOrUpgrade()) { final long uptimeMillis = SystemClock.elapsedRealtime(); - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, - StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_READY, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_READY, uptimeMillis); final long maxUptimeMillis = 60 * 1000; if (uptimeMillis > maxUptimeMillis) { @@ -807,8 +808,9 @@ public final class SystemServer { // Start the package manager. if (!mRuntimeRestart) { - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, - StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__PACKAGE_MANAGER_INIT_START, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + FrameworkStatsLog + .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__PACKAGE_MANAGER_INIT_START, SystemClock.elapsedRealtime()); } @@ -825,8 +827,9 @@ public final class SystemServer { mPackageManager = mSystemContext.getPackageManager(); t.traceEnd(); if (!mRuntimeRestart && !isFirstBootOrUpgrade()) { - StatsLog.write(StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, - StatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__PACKAGE_MANAGER_INIT_READY, + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + FrameworkStatsLog + .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__PACKAGE_MANAGER_INIT_READY, SystemClock.elapsedRealtime()); } // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename diff --git a/services/people/java/com/android/server/people/SessionInfo.java b/services/people/java/com/android/server/people/SessionInfo.java index eb08e03c14de..eaa0781f12ef 100644 --- a/services/people/java/com/android/server/people/SessionInfo.java +++ b/services/people/java/com/android/server/people/SessionInfo.java @@ -25,7 +25,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.server.people.data.DataManager; -import com.android.server.people.prediction.ConversationPredictor; +import com.android.server.people.prediction.AppTargetPredictor; import java.util.List; @@ -34,12 +34,12 @@ class SessionInfo { private static final String TAG = "SessionInfo"; - private final ConversationPredictor mConversationPredictor; + private final AppTargetPredictor mAppTargetPredictor; private final RemoteCallbackList<IPredictionCallback> mCallbacks = new RemoteCallbackList<>(); SessionInfo(AppPredictionContext predictionContext, DataManager dataManager) { - mConversationPredictor = new ConversationPredictor(predictionContext, + mAppTargetPredictor = AppTargetPredictor.create(predictionContext, this::updatePredictions, dataManager); } @@ -51,8 +51,8 @@ class SessionInfo { mCallbacks.unregister(callback); } - ConversationPredictor getPredictor() { - return mConversationPredictor; + AppTargetPredictor getPredictor() { + return mAppTargetPredictor; } void onDestroy() { diff --git a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java new file mode 100644 index 000000000000..d825b6b2bd8f --- /dev/null +++ b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java @@ -0,0 +1,121 @@ +/* + * 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.server.people.data; + +import android.annotation.WorkerThread; +import android.content.Context; +import android.database.Cursor; +import android.provider.CallLog.Calls; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseIntArray; + +import java.util.function.BiConsumer; + +/** A helper class that queries the call log database. */ +class CallLogQueryHelper { + + private static final String TAG = "CallLogQueryHelper"; + + private static final SparseIntArray CALL_TYPE_TO_EVENT_TYPE = new SparseIntArray(); + + static { + CALL_TYPE_TO_EVENT_TYPE.put(Calls.INCOMING_TYPE, Event.TYPE_CALL_INCOMING); + CALL_TYPE_TO_EVENT_TYPE.put(Calls.OUTGOING_TYPE, Event.TYPE_CALL_OUTGOING); + CALL_TYPE_TO_EVENT_TYPE.put(Calls.MISSED_TYPE, Event.TYPE_CALL_MISSED); + } + + private final Context mContext; + private final BiConsumer<String, Event> mEventConsumer; + private long mLastCallTimestamp; + + /** + * @param context Context for accessing the content resolver. + * @param eventConsumer Consumes the events created from the call log records. The first input + * param is the normalized phone number. + */ + CallLogQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + mContext = context; + mEventConsumer = eventConsumer; + } + + /** + * Queries the call log database for the new data added since {@code sinceTime} and returns + * true if the query runs successfully and at least one call log entry is found. + */ + @WorkerThread + boolean querySince(long sinceTime) { + String[] projection = new String[] { + Calls.CACHED_NORMALIZED_NUMBER, Calls.DATE, Calls.DURATION, Calls.TYPE }; + String selection = Calls.DATE + " > ?"; + String[] selectionArgs = new String[] { Long.toString(sinceTime) }; + boolean hasResults = false; + try (Cursor cursor = mContext.getContentResolver().query( + Calls.CONTENT_URI, projection, selection, selectionArgs, + Calls.DEFAULT_SORT_ORDER)) { + if (cursor == null) { + Slog.w(TAG, "Cursor is null when querying call log."); + return false; + } + while (cursor.moveToNext()) { + // Phone number + int numberIndex = cursor.getColumnIndex(Calls.CACHED_NORMALIZED_NUMBER); + String phoneNumber = cursor.getString(numberIndex); + + // Date + int dateIndex = cursor.getColumnIndex(Calls.DATE); + long date = cursor.getLong(dateIndex); + + // Duration + int durationIndex = cursor.getColumnIndex(Calls.DURATION); + long durationSeconds = cursor.getLong(durationIndex); + + // Type + int typeIndex = cursor.getColumnIndex(Calls.TYPE); + int callType = cursor.getInt(typeIndex); + + mLastCallTimestamp = Math.max(mLastCallTimestamp, date); + if (addEvent(phoneNumber, date, durationSeconds, callType)) { + hasResults = true; + } + } + } + return hasResults; + } + + long getLastCallTimestamp() { + return mLastCallTimestamp; + } + + private boolean addEvent(String phoneNumber, long date, long durationSeconds, int callType) { + if (!validateEvent(phoneNumber, date, callType)) { + return false; + } + @Event.EventType int eventType = CALL_TYPE_TO_EVENT_TYPE.get(callType); + Event event = new Event.Builder(date, eventType) + .setCallDetails(new Event.CallDetails(durationSeconds)) + .build(); + mEventConsumer.accept(phoneNumber, event); + return true; + } + + private boolean validateEvent(String phoneNumber, long date, int callType) { + return !TextUtils.isEmpty(phoneNumber) + && date > 0L + && CALL_TYPE_TO_EVENT_TYPE.indexOfKey(callType) >= 0; + } +} diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 13cce414ea7c..79503f797318 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -45,7 +45,9 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.provider.CallLog; import android.provider.ContactsContract.Contacts; +import android.provider.Telephony.MmsSms; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.telecom.TelecomManager; @@ -59,13 +61,13 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.telephony.SmsApplication; import com.android.server.LocalServices; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -77,7 +79,7 @@ public class DataManager { private static final String PLATFORM_PACKAGE_NAME = "android"; private static final int MY_UID = Process.myUid(); private static final int MY_PID = Process.myPid(); - private static final long USAGE_STATS_QUERY_MAX_EVENT_AGE_MS = DateUtils.DAY_IN_MILLIS; + private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS; private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L; private final Context mContext; @@ -90,6 +92,8 @@ public class DataManager { private final SparseArray<ScheduledFuture<?>> mUsageStatsQueryFutures = new SparseArray<>(); private final SparseArray<NotificationListenerService> mNotificationListeners = new SparseArray<>(); + private final ContentObserver mCallLogContentObserver; + private final ContentObserver mMmsSmsContentObserver; private ShortcutServiceInternal mShortcutServiceInternal; private UsageStatsManagerInternal mUsageStatsManagerInternal; @@ -97,9 +101,7 @@ public class DataManager { private UserManager mUserManager; public DataManager(Context context) { - mContext = context; - mInjector = new Injector(); - mUsageStatsQueryExecutor = mInjector.createScheduledExecutor(); + this(context, new Injector()); } @VisibleForTesting @@ -107,6 +109,10 @@ public class DataManager { mContext = context; mInjector = injector; mUsageStatsQueryExecutor = mInjector.createScheduledExecutor(); + mCallLogContentObserver = new CallLogContentObserver( + BackgroundThread.getHandler()); + mMmsSmsContentObserver = new MmsSmsContentObserver( + BackgroundThread.getHandler()); } /** Initialization. Called when the system services are up running. */ @@ -159,6 +165,18 @@ public class DataManager { } catch (RemoteException e) { // Should never occur for local calls. } + + if (userId == UserHandle.USER_SYSTEM) { + // The call log and MMS/SMS messages are shared across user profiles. So only need to + // register the content observers once for the primary user. + // TODO: Register observers after the conversations and events being loaded from disk. + mContext.getContentResolver().registerContentObserver( + CallLog.CONTENT_URI, /* notifyForDescendants= */ true, + mCallLogContentObserver, UserHandle.USER_SYSTEM); + mContext.getContentResolver().registerContentObserver( + MmsSms.CONTENT_URI, /* notifyForDescendants= */ false, + mMmsSmsContentObserver, UserHandle.USER_SYSTEM); + } } /** This method is called when a user is stopped. */ @@ -183,6 +201,10 @@ public class DataManager { // Should never occur for local calls. } } + if (userId == UserHandle.USER_SYSTEM) { + mContext.getContentResolver().unregisterContentObserver(mCallLogContentObserver); + mContext.getContentResolver().unregisterContentObserver(mMmsSmsContentObserver); + } } /** @@ -199,6 +221,13 @@ public class DataManager { } } + /** Gets the {@link PackageData} for the given package and user. */ + @Nullable + public PackageData getPackage(@NonNull String packageName, @UserIdInt int userId) { + UserData userData = getUnlockedUserData(userId); + return userData != null ? userData.getPackageData(packageName) : null; + } + /** Gets the {@link ShortcutInfo} for the given shortcut ID. */ @Nullable public ShortcutInfo getShortcut(@NonNull String packageName, @UserIdInt int userId, @@ -212,20 +241,11 @@ public class DataManager { } /** - * Gets the conversation {@link ShareShortcutInfo}s from all packages owned by the calling user - * that match the specified {@link IntentFilter}. + * Gets the {@link ShareShortcutInfo}s from all packages owned by the calling user that match + * the specified {@link IntentFilter}. */ - public List<ShareShortcutInfo> getConversationShareTargets( - @NonNull IntentFilter intentFilter) { - List<ShareShortcutInfo> shareShortcuts = mShortcutManager.getShareTargets(intentFilter); - List<ShareShortcutInfo> result = new ArrayList<>(); - for (ShareShortcutInfo shareShortcut : shareShortcuts) { - ShortcutInfo si = shareShortcut.getShortcutInfo(); - if (getConversationInfo(si.getPackage(), si.getUserId(), si.getId()) != null) { - result.add(shareShortcut); - } - } - return result; + public List<ShareShortcutInfo> getShareShortcuts(@NonNull IntentFilter intentFilter) { + return mShortcutManager.getShareTargets(intentFilter); } /** Reports the {@link AppTargetEvent} from App Prediction Manager. */ @@ -236,7 +256,7 @@ public class DataManager { if (shortcutInfo == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) { return; } - PackageData packageData = getPackageData(appTarget.getPackageName(), + PackageData packageData = getPackage(appTarget.getPackageName(), appTarget.getUser().getIdentifier()); if (packageData == null) { return; @@ -277,26 +297,21 @@ public class DataManager { userId, MY_PID, MY_UID); } + private void forAllUnlockedUsers(Consumer<UserData> consumer) { + for (int i = 0; i < mUserDataArray.size(); i++) { + UserData userData = mUserDataArray.get(i); + if (userData.isUnlocked()) { + consumer.accept(userData); + } + } + } + @Nullable private UserData getUnlockedUserData(int userId) { UserData userData = mUserDataArray.get(userId); return userData != null && userData.isUnlocked() ? userData : null; } - @Nullable - private PackageData getPackageData(@NonNull String packageName, int userId) { - UserData userData = getUnlockedUserData(userId); - return userData != null ? userData.getPackageData(packageName) : null; - } - - @Nullable - private ConversationInfo getConversationInfo(@NonNull String packageName, @UserIdInt int userId, - @NonNull String shortcutId) { - PackageData packageData = getPackageData(packageName, userId); - return packageData != null ? packageData.getConversationStore().getConversation(shortcutId) - : null; - } - private void updateDefaultDialer(@NonNull UserData userData) { TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); String defaultDialer = telecomManager != null @@ -318,7 +333,7 @@ public class DataManager { if (shortcutId == null) { return null; } - PackageData packageData = getPackageData(sbn.getPackageName(), + PackageData packageData = getPackage(sbn.getPackageName(), sbn.getUser().getIdentifier()); if (packageData == null || packageData.getConversationStore().getConversation(shortcutId) == null) { @@ -373,7 +388,7 @@ public class DataManager { @WorkerThread void queryUsageStatsService(@UserIdInt int userId, long currentTime, long lastQueryTime) { UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser( - userId, lastQueryTime, currentTime, false); + userId, lastQueryTime, currentTime, false, false); if (usageEvents == null) { return; } @@ -382,7 +397,7 @@ public class DataManager { usageEvents.getNextEvent(e); String packageName = e.getPackageName(); - PackageData packageData = getPackageData(packageName, userId); + PackageData packageData = getPackage(packageName, userId); if (packageData == null) { continue; } @@ -405,10 +420,25 @@ public class DataManager { } @VisibleForTesting + ContentObserver getCallLogContentObserverForTesting() { + return mCallLogContentObserver; + } + + @VisibleForTesting + ContentObserver getMmsSmsContentObserverForTesting() { + return mMmsSmsContentObserver; + } + + @VisibleForTesting NotificationListenerService getNotificationListenerServiceForTesting(@UserIdInt int userId) { return mNotificationListeners.get(userId); } + @VisibleForTesting + UserData getUserDataForTesting(@UserIdInt int userId) { + return mUserDataArray.get(userId); + } + /** Observer that observes the changes in the Contacts database. */ private class ContactsContentObserver extends ContentObserver { @@ -459,6 +489,88 @@ public class DataManager { } } + /** Observer that observes the changes in the call log database. */ + private class CallLogContentObserver extends ContentObserver implements + BiConsumer<String, Event> { + + private final CallLogQueryHelper mCallLogQueryHelper; + private long mLastCallTimestamp; + + private CallLogContentObserver(Handler handler) { + super(handler); + mCallLogQueryHelper = mInjector.createCallLogQueryHelper(mContext, this); + mLastCallTimestamp = System.currentTimeMillis() - QUERY_EVENTS_MAX_AGE_MS; + } + + @Override + public void onChange(boolean selfChange) { + if (mCallLogQueryHelper.querySince(mLastCallTimestamp)) { + mLastCallTimestamp = mCallLogQueryHelper.getLastCallTimestamp(); + } + } + + @Override + public void accept(String phoneNumber, Event event) { + forAllUnlockedUsers(userData -> { + PackageData defaultDialer = userData.getDefaultDialer(); + if (defaultDialer == null) { + return; + } + ConversationStore conversationStore = defaultDialer.getConversationStore(); + if (conversationStore.getConversationByPhoneNumber(phoneNumber) == null) { + return; + } + EventStore eventStore = defaultDialer.getEventStore(); + eventStore.getOrCreateCallEventHistory(phoneNumber).addEvent(event); + }); + } + } + + /** Observer that observes the changes in the MMS & SMS database. */ + private class MmsSmsContentObserver extends ContentObserver implements + BiConsumer<String, Event> { + + private final MmsQueryHelper mMmsQueryHelper; + private long mLastMmsTimestamp; + + private final SmsQueryHelper mSmsQueryHelper; + private long mLastSmsTimestamp; + + private MmsSmsContentObserver(Handler handler) { + super(handler); + mMmsQueryHelper = mInjector.createMmsQueryHelper(mContext, this); + mSmsQueryHelper = mInjector.createSmsQueryHelper(mContext, this); + mLastSmsTimestamp = mLastMmsTimestamp = + System.currentTimeMillis() - QUERY_EVENTS_MAX_AGE_MS; + } + + @Override + public void onChange(boolean selfChange) { + if (mMmsQueryHelper.querySince(mLastMmsTimestamp)) { + mLastMmsTimestamp = mMmsQueryHelper.getLastMessageTimestamp(); + } + if (mSmsQueryHelper.querySince(mLastSmsTimestamp)) { + mLastSmsTimestamp = mSmsQueryHelper.getLastMessageTimestamp(); + } + } + + @Override + public void accept(String phoneNumber, Event event) { + forAllUnlockedUsers(userData -> { + PackageData defaultSmsApp = userData.getDefaultSmsApp(); + if (defaultSmsApp == null) { + return; + } + ConversationStore conversationStore = defaultSmsApp.getConversationStore(); + if (conversationStore.getConversationByPhoneNumber(phoneNumber) == null) { + return; + } + EventStore eventStore = defaultSmsApp.getEventStore(); + eventStore.getOrCreateSmsEventHistory(phoneNumber).addEvent(event); + }); + } + } + /** Listener for the shortcut data changes. */ private class ShortcutServiceListener implements ShortcutServiceInternal.ShortcutChangeListener { @@ -504,7 +616,7 @@ public class DataManager { private UsageStatsQueryRunnable(int userId) { mUserId = userId; - mLastQueryTime = System.currentTimeMillis() - USAGE_STATS_QUERY_MAX_EVENT_AGE_MS; + mLastQueryTime = System.currentTimeMillis() - QUERY_EVENTS_MAX_AGE_MS; } @Override @@ -552,6 +664,21 @@ public class DataManager { return new ContactsQueryHelper(context); } + CallLogQueryHelper createCallLogQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + return new CallLogQueryHelper(context, eventConsumer); + } + + MmsQueryHelper createMmsQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + return new MmsQueryHelper(context, eventConsumer); + } + + SmsQueryHelper createSmsQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + return new SmsQueryHelper(context, eventConsumer); + } + int getCallingUserId() { return Binder.getCallingUserHandle().getIdentifier(); } diff --git a/services/people/java/com/android/server/people/data/MmsQueryHelper.java b/services/people/java/com/android/server/people/data/MmsQueryHelper.java new file mode 100644 index 000000000000..1e485c082d18 --- /dev/null +++ b/services/people/java/com/android/server/people/data/MmsQueryHelper.java @@ -0,0 +1,151 @@ +/* + * 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.server.people.data; + +import android.annotation.Nullable; +import android.annotation.WorkerThread; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Telephony.BaseMmsColumns; +import android.provider.Telephony.Mms; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseIntArray; + +import com.google.android.mms.pdu.PduHeaders; + +import java.util.function.BiConsumer; + +/** A helper class that queries the MMS database tables. */ +class MmsQueryHelper { + + private static final String TAG = "MmsQueryHelper"; + private static final long MILLIS_PER_SECONDS = 1000L; + private static final SparseIntArray MSG_BOX_TO_EVENT_TYPE = new SparseIntArray(); + + static { + MSG_BOX_TO_EVENT_TYPE.put(BaseMmsColumns.MESSAGE_BOX_INBOX, Event.TYPE_SMS_INCOMING); + MSG_BOX_TO_EVENT_TYPE.put(BaseMmsColumns.MESSAGE_BOX_SENT, Event.TYPE_SMS_OUTGOING); + } + + private final Context mContext; + private final BiConsumer<String, Event> mEventConsumer; + private long mLastMessageTimestamp; + private String mCurrentCountryIso; + + /** + * @param context Context for accessing the content resolver. + * @param eventConsumer Consumes the events created from the message records. The first input + * param is the normalized phone number. + */ + MmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + mContext = context; + mEventConsumer = eventConsumer; + mCurrentCountryIso = Utils.getCurrentCountryIso(mContext); + } + + /** + * Queries the MMS database tables for the new data added since {@code sinceTime} (in millis) + * and returns true if the query runs successfully and at least one message entry is found. + */ + @WorkerThread + boolean querySince(long sinceTime) { + String[] projection = new String[] { Mms._ID, Mms.DATE, Mms.MESSAGE_BOX }; + String selection = Mms.DATE + " > ?"; + // NOTE: The field Mms.DATE is stored in seconds, not milliseconds. + String[] selectionArgs = new String[] { Long.toString(sinceTime / MILLIS_PER_SECONDS) }; + boolean hasResults = false; + try (Cursor cursor = mContext.getContentResolver().query( + Mms.CONTENT_URI, projection, selection, selectionArgs, null)) { + if (cursor == null) { + Slog.w(TAG, "Cursor is null when querying MMS table."); + return false; + } + while (cursor.moveToNext()) { + // ID + int msgIdIndex = cursor.getColumnIndex(Mms._ID); + String msgId = cursor.getString(msgIdIndex); + + // Date + int dateIndex = cursor.getColumnIndex(Mms.DATE); + long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS; + + // Message box + int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX); + int msgBox = cursor.getInt(msgBoxIndex); + + mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date); + String address = getMmsAddress(msgId, msgBox); + if (address != null && addEvent(address, date, msgBox)) { + hasResults = true; + } + } + } + return hasResults; + } + + long getLastMessageTimestamp() { + return mLastMessageTimestamp; + } + + @Nullable + private String getMmsAddress(String msgId, int msgBox) { + Uri addressUri = Mms.Addr.getAddrUriForMessage(msgId); + String[] projection = new String[] { Mms.Addr.ADDRESS, Mms.Addr.TYPE }; + String address = null; + try (Cursor cursor = mContext.getContentResolver().query( + addressUri, projection, null, null, null)) { + if (cursor == null) { + Slog.w(TAG, "Cursor is null when querying MMS address table."); + return null; + } + while (cursor.moveToNext()) { + // Type + int typeIndex = cursor.getColumnIndex(Mms.Addr.TYPE); + int type = cursor.getInt(typeIndex); + + if ((msgBox == BaseMmsColumns.MESSAGE_BOX_INBOX && type == PduHeaders.FROM) + || (msgBox == BaseMmsColumns.MESSAGE_BOX_SENT && type == PduHeaders.TO)) { + // Address + int addrIndex = cursor.getColumnIndex(Mms.Addr.ADDRESS); + address = cursor.getString(addrIndex); + } + } + } + if (!Mms.isPhoneNumber(address)) { + return null; + } + return PhoneNumberUtils.formatNumberToE164(address, mCurrentCountryIso); + } + + private boolean addEvent(String phoneNumber, long date, int msgBox) { + if (!validateEvent(phoneNumber, date, msgBox)) { + return false; + } + @Event.EventType int eventType = MSG_BOX_TO_EVENT_TYPE.get(msgBox); + mEventConsumer.accept(phoneNumber, new Event(date, eventType)); + return true; + } + + private boolean validateEvent(String phoneNumber, long date, int msgBox) { + return !TextUtils.isEmpty(phoneNumber) + && date > 0L + && MSG_BOX_TO_EVENT_TYPE.indexOfKey(msgBox) >= 0; + } +} diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java index 9c22a7f1c484..75b870c74591 100644 --- a/services/people/java/com/android/server/people/data/PackageData.java +++ b/services/people/java/com/android/server/people/data/PackageData.java @@ -17,11 +17,13 @@ package com.android.server.people.data; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.LocusId; import android.text.TextUtils; import java.util.function.Consumer; +import java.util.function.Predicate; /** The data associated with a package. */ public class PackageData { @@ -37,15 +39,19 @@ public class PackageData { @NonNull private final EventStore mEventStore; - private boolean mIsDefaultDialer; + private final Predicate<String> mIsDefaultDialerPredicate; - private boolean mIsDefaultSmsApp; + private final Predicate<String> mIsDefaultSmsAppPredicate; - PackageData(@NonNull String packageName, @UserIdInt int userId) { + PackageData(@NonNull String packageName, @UserIdInt int userId, + @NonNull Predicate<String> isDefaultDialerPredicate, + @NonNull Predicate<String> isDefaultSmsAppPredicate) { mPackageName = packageName; mUserId = userId; mConversationStore = new ConversationStore(); mEventStore = new EventStore(); + mIsDefaultDialerPredicate = isDefaultDialerPredicate; + mIsDefaultSmsAppPredicate = isDefaultSmsAppPredicate; } @NonNull @@ -68,6 +74,15 @@ public class PackageData { } /** + * Gets the {@link ConversationInfo} for a given shortcut ID. Returns null if such as {@link + * ConversationInfo} does not exist. + */ + @Nullable + public ConversationInfo getConversationInfo(@NonNull String shortcutId) { + return getConversationStore().getConversation(shortcutId); + } + + /** * Gets the combined {@link EventHistory} for a given shortcut ID. This returned {@link * EventHistory} has events of all types, no matter whether they're annotated with shortcut ID, * Locus ID, or phone number etc. @@ -114,11 +129,11 @@ public class PackageData { } public boolean isDefaultDialer() { - return mIsDefaultDialer; + return mIsDefaultDialerPredicate.test(mPackageName); } public boolean isDefaultSmsApp() { - return mIsDefaultSmsApp; + return mIsDefaultSmsAppPredicate.test(mPackageName); } @NonNull @@ -131,14 +146,6 @@ public class PackageData { return mEventStore; } - void setIsDefaultDialer(boolean value) { - mIsDefaultDialer = value; - } - - void setIsDefaultSmsApp(boolean value) { - mIsDefaultSmsApp = value; - } - void onDestroy() { // TODO: STOPSHIP: Implements this method for the case of package being uninstalled. } diff --git a/services/people/java/com/android/server/people/data/SmsQueryHelper.java b/services/people/java/com/android/server/people/data/SmsQueryHelper.java new file mode 100644 index 000000000000..c38c846bf461 --- /dev/null +++ b/services/people/java/com/android/server/people/data/SmsQueryHelper.java @@ -0,0 +1,119 @@ +/* + * 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.server.people.data; + +import android.annotation.WorkerThread; +import android.content.Context; +import android.database.Cursor; +import android.provider.Telephony.Sms; +import android.provider.Telephony.TextBasedSmsColumns; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseIntArray; + +import java.util.function.BiConsumer; + +/** A helper class that queries the SMS database table. */ +class SmsQueryHelper { + + private static final String TAG = "SmsQueryHelper"; + private static final SparseIntArray SMS_TYPE_TO_EVENT_TYPE = new SparseIntArray(); + + static { + SMS_TYPE_TO_EVENT_TYPE.put(TextBasedSmsColumns.MESSAGE_TYPE_INBOX, Event.TYPE_SMS_INCOMING); + SMS_TYPE_TO_EVENT_TYPE.put(TextBasedSmsColumns.MESSAGE_TYPE_SENT, Event.TYPE_SMS_OUTGOING); + } + + private final Context mContext; + private final BiConsumer<String, Event> mEventConsumer; + private final String mCurrentCountryIso; + private long mLastMessageTimestamp; + + /** + * @param context Context for accessing the content resolver. + * @param eventConsumer Consumes the events created from the message records. The first input + * param is the normalized phone number. + */ + SmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + mContext = context; + mEventConsumer = eventConsumer; + mCurrentCountryIso = Utils.getCurrentCountryIso(mContext); + } + + /** + * Queries the SMS database tables for the new data added since {@code sinceTime} (in millis) + * and returns true if the query runs successfully and at least one message entry is found. + */ + @WorkerThread + boolean querySince(long sinceTime) { + String[] projection = new String[] { Sms._ID, Sms.DATE, Sms.TYPE, Sms.ADDRESS }; + String selection = Sms.DATE + " > ?"; + String[] selectionArgs = new String[] { Long.toString(sinceTime) }; + boolean hasResults = false; + try (Cursor cursor = mContext.getContentResolver().query( + Sms.CONTENT_URI, projection, selection, selectionArgs, null)) { + if (cursor == null) { + Slog.w(TAG, "Cursor is null when querying SMS table."); + return false; + } + while (cursor.moveToNext()) { + // ID + int msgIdIndex = cursor.getColumnIndex(Sms._ID); + String msgId = cursor.getString(msgIdIndex); + + // Date + int dateIndex = cursor.getColumnIndex(Sms.DATE); + long date = cursor.getLong(dateIndex); + + // Type + int typeIndex = cursor.getColumnIndex(Sms.TYPE); + int type = cursor.getInt(typeIndex); + + // Address + int addressIndex = cursor.getColumnIndex(Sms.ADDRESS); + String address = PhoneNumberUtils.formatNumberToE164( + cursor.getString(addressIndex), mCurrentCountryIso); + + mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date); + if (address != null && addEvent(address, date, type)) { + hasResults = true; + } + } + } + return hasResults; + } + + long getLastMessageTimestamp() { + return mLastMessageTimestamp; + } + + private boolean addEvent(String phoneNumber, long date, int type) { + if (!validateEvent(phoneNumber, date, type)) { + return false; + } + @Event.EventType int eventType = SMS_TYPE_TO_EVENT_TYPE.get(type); + mEventConsumer.accept(phoneNumber, new Event(date, eventType)); + return true; + } + + private boolean validateEvent(String phoneNumber, long date, int type) { + return !TextUtils.isEmpty(phoneNumber) + && date > 0L + && SMS_TYPE_TO_EVENT_TYPE.indexOfKey(type) >= 0; + } +} diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java index 2c16059e89ba..4e8fd16d05fd 100644 --- a/services/people/java/com/android/server/people/data/UserData.java +++ b/services/people/java/com/android/server/people/data/UserData.java @@ -34,6 +34,12 @@ class UserData { private Map<String, PackageData> mPackageDataMap = new ArrayMap<>(); + @Nullable + private String mDefaultDialer; + + @Nullable + private String mDefaultSmsApp; + UserData(@UserIdInt int userId) { mUserId = userId; } @@ -66,8 +72,7 @@ class UserData { */ @NonNull PackageData getOrCreatePackageData(String packageName) { - return mPackageDataMap.computeIfAbsent( - packageName, key -> new PackageData(packageName, mUserId)); + return mPackageDataMap.computeIfAbsent(packageName, key -> createPackageData(packageName)); } /** @@ -80,24 +85,32 @@ class UserData { } void setDefaultDialer(@Nullable String packageName) { - for (PackageData packageData : mPackageDataMap.values()) { - if (packageData.isDefaultDialer()) { - packageData.setIsDefaultDialer(false); - } - if (TextUtils.equals(packageName, packageData.getPackageName())) { - packageData.setIsDefaultDialer(true); - } - } + mDefaultDialer = packageName; + } + + @Nullable + PackageData getDefaultDialer() { + return mDefaultDialer != null ? getPackageData(mDefaultDialer) : null; } void setDefaultSmsApp(@Nullable String packageName) { - for (PackageData packageData : mPackageDataMap.values()) { - if (packageData.isDefaultSmsApp()) { - packageData.setIsDefaultSmsApp(false); - } - if (TextUtils.equals(packageName, packageData.getPackageName())) { - packageData.setIsDefaultSmsApp(true); - } - } + mDefaultSmsApp = packageName; + } + + @Nullable + PackageData getDefaultSmsApp() { + return mDefaultSmsApp != null ? getPackageData(mDefaultSmsApp) : null; + } + + private PackageData createPackageData(String packageName) { + return new PackageData(packageName, mUserId, this::isDefaultDialer, this::isDefaultSmsApp); + } + + private boolean isDefaultDialer(String packageName) { + return TextUtils.equals(mDefaultDialer, packageName); + } + + private boolean isDefaultSmsApp(String packageName) { + return TextUtils.equals(mDefaultSmsApp, packageName); } } diff --git a/services/people/java/com/android/server/people/data/Utils.java b/services/people/java/com/android/server/people/data/Utils.java new file mode 100644 index 000000000000..b7529605f462 --- /dev/null +++ b/services/people/java/com/android/server/people/data/Utils.java @@ -0,0 +1,49 @@ +/* + * 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.server.people.data; + +import android.content.Context; +import android.location.Country; +import android.location.CountryDetector; + +import java.util.Locale; + +/** The utilities static methods for people service data package. */ +class Utils { + + /** + * @return The ISO 3166-1 two letters country code of the country the user is in. + */ + static String getCurrentCountryIso(Context context) { + String countryIso = null; + CountryDetector detector = (CountryDetector) context.getSystemService( + Context.COUNTRY_DETECTOR); + if (detector != null) { + Country country = detector.detectCountry(); + if (country != null) { + countryIso = country.getCountryIso(); + } + } + if (countryIso == null) { + countryIso = Locale.getDefault().getCountry(); + } + return countryIso; + } + + private Utils() { + } +} diff --git a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java new file mode 100644 index 000000000000..44f3e35833d9 --- /dev/null +++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java @@ -0,0 +1,128 @@ +/* + * 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.server.people.prediction; + +import android.annotation.MainThread; +import android.annotation.NonNull; +import android.annotation.WorkerThread; +import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; +import android.app.prediction.AppTargetId; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.people.data.DataManager; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +/** + * Predictor that predicts the {@link AppTarget} the user is most likely to open. + */ +public class AppTargetPredictor { + + private static final String UI_SURFACE_SHARE = "share"; + + /** Creates a {@link AppTargetPredictor} instance based on the prediction context. */ + public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext, + @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, + @NonNull DataManager dataManager) { + if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) { + return new ShareTargetPredictor( + predictionContext, updatePredictionsMethod, dataManager); + } + return new AppTargetPredictor(predictionContext, updatePredictionsMethod, dataManager); + } + + private final AppPredictionContext mPredictionContext; + private final Consumer<List<AppTarget>> mUpdatePredictionsMethod; + private final DataManager mDataManager; + private final ExecutorService mCallbackExecutor; + + AppTargetPredictor(@NonNull AppPredictionContext predictionContext, + @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, + @NonNull DataManager dataManager) { + mPredictionContext = predictionContext; + mUpdatePredictionsMethod = updatePredictionsMethod; + mDataManager = dataManager; + mCallbackExecutor = Executors.newSingleThreadExecutor(); + } + + /** + * Called by the client app to indicate a target launch. + */ + @MainThread + public void onAppTargetEvent(AppTargetEvent event) { + } + + /** + * Called by the client app to indicate a particular location has been shown to the user. + */ + @MainThread + public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) { + } + + /** + * Called by the client app to request sorting of the provided targets based on the prediction + * ranking. + */ + @MainThread + public void onSortAppTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { + mCallbackExecutor.execute(() -> sortTargets(targets, callback)); + } + + /** + * Called by the client app to request target predictions. + */ + @MainThread + public void onRequestPredictionUpdate() { + mCallbackExecutor.execute(this::predictTargets); + } + + @VisibleForTesting + public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { + return mUpdatePredictionsMethod; + } + + /** To be overridden by the subclass to predict the targets. */ + @WorkerThread + void predictTargets() { + } + + /** + * To be overridden by the subclass to sort the provided targets based on the prediction + * ranking. + */ + @WorkerThread + void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { + callback.accept(targets); + } + + AppPredictionContext getPredictionContext() { + return mPredictionContext; + } + + DataManager getDataManager() { + return mDataManager; + } + + void updatePredictions(List<AppTarget> targets) { + mUpdatePredictionsMethod.accept(targets); + } +} diff --git a/services/people/java/com/android/server/people/prediction/ConversationPredictor.java b/services/people/java/com/android/server/people/prediction/ConversationPredictor.java deleted file mode 100644 index ed8a56bb6435..000000000000 --- a/services/people/java/com/android/server/people/prediction/ConversationPredictor.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.people.prediction; - -import android.annotation.MainThread; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.prediction.AppPredictionContext; -import android.app.prediction.AppTarget; -import android.app.prediction.AppTargetEvent; -import android.app.prediction.AppTargetId; -import android.content.IntentFilter; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager.ShareShortcutInfo; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.ChooserActivity; -import com.android.server.people.data.DataManager; -import com.android.server.people.data.EventHistory; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Consumer; - -/** - * Predictor that predicts the conversations or apps the user is most likely to open. - */ -public class ConversationPredictor { - - private static final String UI_SURFACE_SHARE = "share"; - - private final AppPredictionContext mPredictionContext; - private final Consumer<List<AppTarget>> mUpdatePredictionsMethod; - private final DataManager mDataManager; - private final ExecutorService mCallbackExecutor; - @Nullable - private final IntentFilter mIntentFilter; - - public ConversationPredictor(@NonNull AppPredictionContext predictionContext, - @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, - @NonNull DataManager dataManager) { - mPredictionContext = predictionContext; - mUpdatePredictionsMethod = updatePredictionsMethod; - mDataManager = dataManager; - mCallbackExecutor = Executors.newSingleThreadExecutor(); - if (UI_SURFACE_SHARE.equals(mPredictionContext.getUiSurface())) { - mIntentFilter = mPredictionContext.getExtras().getParcelable( - ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); - } else { - mIntentFilter = null; - } - } - - /** - * Called by the client app to indicate a target launch. - */ - @MainThread - public void onAppTargetEvent(AppTargetEvent event) { - mDataManager.reportAppTargetEvent(event, mIntentFilter); - } - - /** - * Called by the client app to indicate a particular location has been shown to the user. - */ - @MainThread - public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) {} - - /** - * Called by the client app to request sorting of the provided targets based on the prediction - * ranking. - */ - @MainThread - public void onSortAppTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { - mCallbackExecutor.execute(() -> callback.accept(targets)); - } - - /** - * Called by the client app to request target predictions. - */ - @MainThread - public void onRequestPredictionUpdate() { - // TODO: Re-route the call to different ranking classes for different surfaces. - mCallbackExecutor.execute(() -> { - List<AppTarget> targets = new ArrayList<>(); - if (mIntentFilter != null) { - List<ShareShortcutInfo> shareShortcuts = - mDataManager.getConversationShareTargets(mIntentFilter); - for (ShareShortcutInfo shareShortcut : shareShortcuts) { - ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); - AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); - String shareTargetClass = shareShortcut.getTargetComponent().getClassName(); - targets.add(new AppTarget.Builder(appTargetId, shortcutInfo) - .setClassName(shareTargetClass) - .build()); - } - } else { - List<ConversationData> conversationDataList = new ArrayList<>(); - mDataManager.forAllPackages(packageData -> - packageData.forAllConversations(conversationInfo -> { - EventHistory eventHistory = packageData.getEventHistory( - conversationInfo.getShortcutId()); - ConversationData conversationData = new ConversationData( - packageData.getPackageName(), packageData.getUserId(), - conversationInfo, eventHistory); - conversationDataList.add(conversationData); - })); - for (ConversationData conversationData : conversationDataList) { - String shortcutId = conversationData.getConversationInfo().getShortcutId(); - ShortcutInfo shortcut = mDataManager.getShortcut( - conversationData.getPackageName(), conversationData.getUserId(), - shortcutId); - if (shortcut != null) { - AppTargetId appTargetId = new AppTargetId(shortcut.getId()); - targets.add(new AppTarget.Builder(appTargetId, shortcut).build()); - } - } - } - mUpdatePredictionsMethod.accept(targets); - }); - } - - @VisibleForTesting - public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { - return mUpdatePredictionsMethod; - } -} diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java new file mode 100644 index 000000000000..280ced3a07c5 --- /dev/null +++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java @@ -0,0 +1,139 @@ +/* + * 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.server.people.prediction; + +import android.annotation.MainThread; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.WorkerThread; +import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; +import android.app.prediction.AppTargetId; +import android.content.IntentFilter; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager.ShareShortcutInfo; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.ChooserActivity; +import com.android.server.people.data.ConversationInfo; +import com.android.server.people.data.DataManager; +import com.android.server.people.data.EventHistory; +import com.android.server.people.data.PackageData; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +class ShareTargetPredictor extends AppTargetPredictor { + + private final IntentFilter mIntentFilter; + + ShareTargetPredictor(@NonNull AppPredictionContext predictionContext, + @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, + @NonNull DataManager dataManager) { + super(predictionContext, updatePredictionsMethod, dataManager); + mIntentFilter = predictionContext.getExtras().getParcelable( + ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); + } + + @MainThread + @Override + public void onAppTargetEvent(AppTargetEvent event) { + getDataManager().reportAppTargetEvent(event, mIntentFilter); + } + + @WorkerThread + @Override + protected void predictTargets() { + List<ShareTarget> shareTargets = getShareTargets(); + // TODO: Rank the share targets with the data in ShareTarget.mConversationData. + List<AppTarget> appTargets = new ArrayList<>(); + for (ShareTarget shareTarget : shareTargets) { + + ShortcutInfo shortcutInfo = shareTarget.getShareShortcutInfo().getShortcutInfo(); + AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); + String shareTargetClassName = + shareTarget.getShareShortcutInfo().getTargetComponent().getClassName(); + AppTarget appTarget = new AppTarget.Builder(appTargetId, shortcutInfo) + .setClassName(shareTargetClassName) + .build(); + appTargets.add(appTarget); + if (appTargets.size() >= getPredictionContext().getPredictedTargetCount()) { + break; + } + } + updatePredictions(appTargets); + } + + @VisibleForTesting + List<ShareTarget> getShareTargets() { + List<ShareTarget> shareTargets = new ArrayList<>(); + List<ShareShortcutInfo> shareShortcuts = + getDataManager().getShareShortcuts(mIntentFilter); + + for (ShareShortcutInfo shareShortcut : shareShortcuts) { + ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); + String packageName = shortcutInfo.getPackage(); + int userId = shortcutInfo.getUserId(); + PackageData packageData = getDataManager().getPackage(packageName, userId); + + ConversationData conversationData = null; + if (packageData != null) { + String shortcutId = shortcutInfo.getId(); + ConversationInfo conversationInfo = + packageData.getConversationInfo(shortcutId); + + if (conversationInfo != null) { + EventHistory eventHistory = packageData.getEventHistory(shortcutId); + conversationData = new ConversationData( + packageName, userId, conversationInfo, eventHistory); + } + } + shareTargets.add(new ShareTarget(shareShortcut, conversationData)); + } + + return shareTargets; + } + + @VisibleForTesting + static class ShareTarget { + + @NonNull + private final ShareShortcutInfo mShareShortcutInfo; + @Nullable + private final ConversationData mConversationData; + + private ShareTarget(@NonNull ShareShortcutInfo shareShortcutInfo, + @Nullable ConversationData conversationData) { + mShareShortcutInfo = shareShortcutInfo; + mConversationData = conversationData; + } + + @NonNull + @VisibleForTesting + ShareShortcutInfo getShareShortcutInfo() { + return mShareShortcutInfo; + } + + @Nullable + @VisibleForTesting + ConversationData getConversationData() { + return mConversationData; + } + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index 6a5de84266e2..bb149cf327b8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -22,6 +22,7 @@ import static android.app.AlarmManager.RTC_WAKEUP; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; +import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; @@ -45,6 +46,7 @@ import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL; import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY; import static com.android.server.AlarmManagerService.Constants.KEY_MIN_INTERVAL; import static com.android.server.AlarmManagerService.IS_WAKEUP_MASK; +import static com.android.server.AlarmManagerService.MILLIS_IN_DAY; import static com.android.server.AlarmManagerService.TIME_CHANGED_MASK; import static com.android.server.AlarmManagerService.WORKING_INDEX; @@ -107,6 +109,7 @@ public class AlarmManagerServiceTest { private static final String TEST_CALLING_PACKAGE = "com.android.framework.test-package"; private static final int SYSTEM_UI_UID = 123456789; private static final int TEST_CALLING_UID = 12345; + private static final long RESTRICTED_WINDOW_MS = MILLIS_IN_DAY; private long mAppStandbyWindow; private AlarmManagerService mService; @@ -485,13 +488,13 @@ public class AlarmManagerServiceTest { anyLong())).thenReturn(standbyBucket); final long firstTrigger = mNowElapsedTest + 10; for (int i = 0; i < quota; i++) { - setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10 + i, + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i, getNewMockPendingIntent()); mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); } // This one should get deferred on set - setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + quota + 10, + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota, getNewMockPendingIntent()); final long expectedNextTrigger = firstTrigger + 1 + mAppStandbyWindow; assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed()); @@ -503,11 +506,11 @@ public class AlarmManagerServiceTest { anyLong())).thenReturn(standbyBucket); final long firstTrigger = mNowElapsedTest + 10; for (int i = 0; i < quota; i++) { - setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10 + i, + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i, getNewMockPendingIntent()); } // This one should get deferred after the latest alarm expires - setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + quota + 10, + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota, getNewMockPendingIntent()); for (int i = 0; i < quota; i++) { mNowElapsedTest = mTestTimer.getElapsed(); @@ -596,6 +599,43 @@ public class AlarmManagerServiceTest { testQuotasNoDeferral(STANDBY_BUCKET_RARE); } + @Test + public void testRestrictedBucketAlarmsDeferredOnSet() throws Exception { + when(mUsageStatsManagerInternal + .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(), anyLong())) + .thenReturn(STANDBY_BUCKET_RESTRICTED); + // This one should go off + final long firstTrigger = mNowElapsedTest + 10; + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger, getNewMockPendingIntent()); + mNowElapsedTest = mTestTimer.getElapsed(); + mTestTimer.expire(); + + // This one should get deferred on set + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + 1, getNewMockPendingIntent()); + final long expectedNextTrigger = + firstTrigger + mService.mConstants.APP_STANDBY_RESTRICTED_WINDOW; + assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed()); + } + + @Test + public void testRestrictedBucketAlarmsDeferredOnExpiration() throws Exception { + when(mUsageStatsManagerInternal + .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(), anyLong())) + .thenReturn(STANDBY_BUCKET_RESTRICTED); + // This one should go off + final long firstTrigger = mNowElapsedTest + 10; + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger, getNewMockPendingIntent()); + + // This one should get deferred after the latest alarm expires + setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + 1, getNewMockPendingIntent()); + + mNowElapsedTest = mTestTimer.getElapsed(); + mTestTimer.expire(); + final long expectedNextTrigger = + firstTrigger + mService.mConstants.APP_STANDBY_RESTRICTED_WINDOW; + assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed()); + } + private void assertAndHandleBucketChanged(int bucket) { when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(), anyLong())).thenReturn(bucket); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 9e1ddb1f8a80..4a40b80a85c1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -109,10 +109,11 @@ public class LocalDisplayAdapterTest { */ @Test public void testPrivateDisplay() throws Exception { - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo())); - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo())); - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo())); + setUpDisplay(new FakeDisplay(PORT_A)); + setUpDisplay(new FakeDisplay(PORT_B)); + setUpDisplay(new FakeDisplay(PORT_C)); updateAvailableDisplays(); + doReturn(new int[]{ PORT_B }).when(mMockedResources) .getIntArray(com.android.internal.R.array.config_localPrivateDisplayPorts); mAdapter.registerLocked(); @@ -135,9 +136,10 @@ public class LocalDisplayAdapterTest { */ @Test public void testPublicDisplaysForNoConfigLocalPrivateDisplayPorts() throws Exception { - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo())); - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo())); + setUpDisplay(new FakeDisplay(PORT_A)); + setUpDisplay(new FakeDisplay(PORT_C)); updateAvailableDisplays(); + // config_localPrivateDisplayPorts is null mAdapter.registerLocked(); @@ -165,9 +167,8 @@ public class LocalDisplayAdapterTest { */ @Test public void testDpiValues() throws Exception { - // needs default one always - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo())); - setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo())); + setUpDisplay(new FakeDisplay(PORT_A)); + setUpDisplay(new FakeDisplay(PORT_B)); updateAvailableDisplays(); mAdapter.registerLocked(); @@ -193,32 +194,32 @@ public class LocalDisplayAdapterTest { assertEquals(expectedDensityDpi, info.densityDpi); } - private class DisplayConfig { + private static class FakeDisplay { public final DisplayAddress.Physical address; - public final IBinder displayToken = new Binder(); - public final SurfaceControl.PhysicalDisplayInfo displayInfo; - - private DisplayConfig( - DisplayAddress.Physical address, SurfaceControl.PhysicalDisplayInfo displayInfo) { - this.address = address; - this.displayInfo = displayInfo; + public final IBinder token = new Binder(); + public final SurfaceControl.DisplayInfo info; + public final SurfaceControl.DisplayConfig config; + + private FakeDisplay(int port) { + this.address = createDisplayAddress(port); + this.info = createFakeDisplayInfo(); + this.config = createFakeDisplayConfig(); } } - private void setUpDisplay(DisplayConfig config) { - mAddresses.add(config.address); - doReturn(config.displayToken).when(() -> - SurfaceControl.getPhysicalDisplayToken(config.address.getPhysicalDisplayId())); - doReturn(new SurfaceControl.PhysicalDisplayInfo[]{ - config.displayInfo - }).when(() -> SurfaceControl.getDisplayConfigs(config.displayToken)); - doReturn(0).when(() -> SurfaceControl.getActiveConfig(config.displayToken)); - doReturn(0).when(() -> SurfaceControl.getActiveColorMode(config.displayToken)); - doReturn(new int[]{ - 0 - }).when(() -> SurfaceControl.getDisplayColorModes(config.displayToken)); + private void setUpDisplay(FakeDisplay display) { + mAddresses.add(display.address); + doReturn(display.token).when(() -> + SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId())); + doReturn(display.info).when(() -> SurfaceControl.getDisplayInfo(display.token)); + doReturn(new SurfaceControl.DisplayConfig[] { display.config }).when( + () -> SurfaceControl.getDisplayConfigs(display.token)); + doReturn(0).when(() -> SurfaceControl.getActiveConfig(display.token)); + doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token)); + doReturn(new int[] { 0 }).when( + () -> SurfaceControl.getDisplayColorModes(display.token)); doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f)) - .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(config.displayToken)); + .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token)); } private void updateAvailableDisplays() { @@ -235,18 +236,21 @@ public class LocalDisplayAdapterTest { return DisplayAddress.fromPortAndModel((byte) port, DISPLAY_MODEL); } - private static SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() { - SurfaceControl.PhysicalDisplayInfo info = new SurfaceControl.PhysicalDisplayInfo(); + private static SurfaceControl.DisplayInfo createFakeDisplayInfo() { + final SurfaceControl.DisplayInfo info = new SurfaceControl.DisplayInfo(); info.density = 100; - info.xDpi = 100; - info.yDpi = 100; - info.secure = false; - info.width = 800; - info.height = 600; - return info; } + private static SurfaceControl.DisplayConfig createFakeDisplayConfig() { + final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig(); + config.width = 800; + config.height = 600; + config.xDpi = 100; + config.yDpi = 100; + return config; + } + private void waitForHandlerToComplete(Handler handler, long waitTimeMs) throws InterruptedException { final Object lock = new Object(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index a4ceadb3028b..9053234aa220 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -89,9 +89,12 @@ public class TouchExplorerTest { @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent); mEvents.add(0, event.copy()); - assertThat(rawEvent, lastEventMatcher); + // LastEvent may not match if we're clearing the state + if (mLastEvent != null) { + MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent); + assertThat(rawEvent, lastEventMatcher); + } } @Override @@ -126,6 +129,31 @@ public class TouchExplorerTest { } @Test + public void upEventWhenInTwoFingerMove_clearsState() { + goFromStateClearTo(STATE_MOVING_2FINGERS); + + send(upEvent()); + assertState(STATE_CLEAR); + } + + @Test + public void clearEventsWhenInTwoFingerMove_clearsStateAndSendsUp() { + goFromStateClearTo(STATE_MOVING_2FINGERS); + + // Clear last event so we don't try to match against anything when cleanup events are sent + // for the clear + mLastEvent = null; + mTouchExplorer.clearEvents(InputDevice.SOURCE_TOUCHSCREEN); + assertState(STATE_CLEAR); + List<MotionEvent> events = getCapturedEvents(); + assertCapturedEvents( + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN, + MotionEvent.ACTION_POINTER_UP, + MotionEvent.ACTION_UP); + } + + @Test public void testTwoFingersDrag_shouldDraggingAndActionDown() { goFromStateClearTo(STATE_DRAGGING_2FINGERS); @@ -268,6 +296,12 @@ public class TouchExplorerTest { DEFAULT_Y, 0)); } + private MotionEvent upEvent() { + MotionEvent event = downEvent(); + event.setAction(MotionEvent.ACTION_UP); + return event; + } + private MotionEvent pointerDownEvent() { final int secondPointerId = 0x0100; final int action = MotionEvent.ACTION_POINTER_DOWN | secondPointerId; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index f7a9e5456156..b193a34952f4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -5817,6 +5817,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.packageName = admin1.getPackageName(); setCrossProfileAppsList(); + setVendorCrossProfileAppsList(); assertTrue(dpm.getAllCrossProfilePackages().isEmpty()); } @@ -5827,6 +5828,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.packageName = admin1.getPackageName(); setCrossProfileAppsList(); + setVendorCrossProfileAppsList(); initializeDpms(); assertTrue(dpm.getAllCrossProfilePackages().isEmpty()); @@ -5839,9 +5841,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setCrossProfilePackages(admin1, packages); setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); + setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); assertEquals(Sets.newSet( - "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"), + "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", + "TEST_VENDOR_DEFAULT_PACKAGE"), dpm.getAllCrossProfilePackages()); } @@ -5854,13 +5858,31 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setCrossProfilePackages(admin1, packages); setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); + setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); initializeDpms(); assertEquals(Sets.newSet( - "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"), + "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", + "TEST_VENDOR_DEFAULT_PACKAGE"), dpm.getAllCrossProfilePackages()); } + public void testGetDefaultCrossProfilePackages_noPackagesSet_returnsEmpty() { + setCrossProfileAppsList(); + setVendorCrossProfileAppsList(); + + assertThat(dpm.getDefaultCrossProfilePackages()).isEmpty(); + } + + public void testGetDefaultCrossProfilePackages_packagesSet_returnsCombinedSet() { + setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); + setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); + + assertThat(dpm.getDefaultCrossProfilePackages()).isEqualTo(Sets.newSet( + "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", "TEST_VENDOR_DEFAULT_PACKAGE" + )); + } + public void testSetCommonCriteriaMode_asDeviceOwner() throws Exception { setDeviceOwner(); @@ -5892,6 +5914,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(packages); } + private void setVendorCrossProfileAppsList(String... packages) { + when(mContext.getResources() + .getStringArray(eq(R.array.vendor_cross_profile_apps))) + .thenReturn(packages); + } + // admin1 is the outgoing DPC, adminAnotherPakcage is the incoming one. private void assertDeviceOwnershipRevertedWithFakeTransferMetadata() throws Exception { writeFakeTransferMetadataFile(UserHandle.USER_SYSTEM, diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index 49ad866a56a4..fd8ccb30c98f 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -23,6 +23,8 @@ import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_UID; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; @@ -43,6 +45,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -103,12 +106,10 @@ public class AppIntegrityManagerServiceImplTest { private static final String PLAY_STORE_PKG = "com.android.vending"; private static final String ADB_INSTALLER = "adb"; - private static final String PLAY_STORE_CERT = - "play_store_cert"; + private static final String PLAY_STORE_CERT = "play_store_cert"; private static final String ADB_CERT = ""; - @org.junit.Rule - public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock PackageManagerInternal mPackageManagerInternal; @Mock Context mMockContext; @@ -134,13 +135,14 @@ public class AppIntegrityManagerServiceImplTest { mPackageManagerInternal, mRuleEvaluationEngine, mIntegrityFileManager, - mHandler); + mHandler, + /* checkIntegrityForRuleProviders= */ true); mSpyPackageManager = spy(mRealContext.getPackageManager()); // setup mocks to prevent NPE when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager); when(mMockContext.getResources()).thenReturn(mMockResources); - when(mMockResources.getStringArray(anyInt())).thenReturn(new String[]{}); + when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {}); when(mIntegrityFileManager.initialized()).thenReturn(true); } @@ -152,8 +154,7 @@ public class AppIntegrityManagerServiceImplTest { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula( - AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -171,8 +172,7 @@ public class AppIntegrityManagerServiceImplTest { whitelistUsAsRuleProvider(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula( - AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -191,8 +191,7 @@ public class AppIntegrityManagerServiceImplTest { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula( - AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), Rule.DENY); // no SecurityException @@ -207,12 +206,7 @@ public class AppIntegrityManagerServiceImplTest { IntentSender mockReceiver = mock(IntentSender.class); List<Rule> rules = Arrays.asList( - new Rule( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - PACKAGE_NAME, - /* isHashedValue= */ false), - Rule.DENY)); + new Rule(IntegrityFormula.PACKAGE_NAME.equalTo(PACKAGE_NAME), Rule.DENY)); mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver); runJobInHandler(); @@ -231,12 +225,7 @@ public class AppIntegrityManagerServiceImplTest { IntentSender mockReceiver = mock(IntentSender.class); List<Rule> rules = Arrays.asList( - new Rule( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - PACKAGE_NAME, - /* isHashedValue= */ false), - Rule.DENY)); + new Rule(IntegrityFormula.PACKAGE_NAME.equalTo(PACKAGE_NAME), Rule.DENY)); mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver); runJobInHandler(); @@ -373,8 +362,8 @@ public class AppIntegrityManagerServiceImplTest { verify(mMockContext) .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any()); Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE); - when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn( - IntegrityCheckResult.deny(/* rule= */ null)); + when(mRuleEvaluationEngine.evaluate(any(), any())) + .thenReturn(IntegrityCheckResult.deny(/* rule= */ null)); broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); runJobInHandler(); @@ -384,10 +373,20 @@ public class AppIntegrityManagerServiceImplTest { 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); } + @Test + public void getCurrentRules() throws Exception { + whitelistUsAsRuleProvider(); + makeUsSystemApp(); + Rule rule = new Rule(IntegrityFormula.PACKAGE_NAME.equalTo("package"), Rule.DENY); + when(mIntegrityFileManager.readRules(any())).thenReturn(Arrays.asList(rule)); + + assertThat(mService.getCurrentRules().getList()).containsExactly(rule); + } + private void whitelistUsAsRuleProvider() { Resources mockResources = mock(Resources.class); when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages)) - .thenReturn(new String[]{TEST_FRAMEWORK_PACKAGE}); + .thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE}); when(mMockContext.getResources()).thenReturn(mockResources); } @@ -409,14 +408,11 @@ public class AppIntegrityManagerServiceImplTest { private Intent makeVerificationIntent() throws Exception { PackageInfo packageInfo = - mRealContext.getPackageManager() + mRealContext + .getPackageManager() .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES); - doReturn(packageInfo) - .when(mSpyPackageManager) - .getPackageInfo(eq(INSTALLER), anyInt()); - doReturn(1) - .when(mSpyPackageManager) - .getPackageUid(eq(INSTALLER), anyInt()); + doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt()); + doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt()); return makeVerificationIntent(INSTALLER); } diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java index ec1423958f8f..6c23ff6fcb3c 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/model/IntegrityCheckResultTest.java @@ -21,7 +21,8 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Rule; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,7 +41,7 @@ public class IntegrityCheckResultTest { assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW); assertThat(allowResult.getMatchedRules()).isEmpty(); assertThat(allowResult.getLoggingResponse()) - .isEqualTo(StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED); + .isEqualTo(FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__ALLOWED); } @Test @@ -58,7 +59,8 @@ public class IntegrityCheckResultTest { assertThat(allowResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.ALLOW); assertThat(allowResult.getMatchedRules()).containsExactly(forceAllowRule); assertThat(allowResult.getLoggingResponse()) - .isEqualTo(StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED); + .isEqualTo( + FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__FORCE_ALLOWED); } @Test @@ -76,7 +78,7 @@ public class IntegrityCheckResultTest { assertThat(denyResult.getEffect()).isEqualTo(IntegrityCheckResult.Effect.DENY); assertThat(denyResult.getMatchedRules()).containsExactly(failedRule); assertThat(denyResult.getLoggingResponse()) - .isEqualTo(StatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED); + .isEqualTo(FrameworkStatsLog.INTEGRITY_CHECK_RESULT_REPORTED__RESPONSE__REJECTED); } @Test diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index b3d949395d5c..b87877907d4f 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -203,8 +203,8 @@ public class RuleBinarySerializerTest { + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) + SERIALIZED_END_INDEXING_KEY + getBits( - DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length, - /* numOfBits= */ 32); + DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length, + /* numOfBits= */ 32); expectedIndexingOutputStream.write( getBytes( expectedIndexingBitsForIndexed @@ -427,8 +427,7 @@ public class RuleBinarySerializerTest { Rule rule = new Rule( new AtomicFormula.LongAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.EQ, - versionCode), + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = @@ -456,8 +455,7 @@ public class RuleBinarySerializerTest { String preInstalled = "1"; Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula( - AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 271e8e27aed4..1ff451b50c42 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -147,6 +147,12 @@ public class LockSettingsServiceTestable extends LockSettingsService { public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) { return mRecoverableKeyStoreManager; } + + @Override + public ManagedProfilePasswordCache getManagedProfilePasswordCache() { + return mock(ManagedProfilePasswordCache.class); + } + } public MockInjector mInjector; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java index 54c552b06c23..b5c6d0425bb1 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java @@ -21,16 +21,22 @@ import static org.junit.Assert.assertThat; import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import javax.crypto.spec.SecretKeySpec; - /** * atest FrameworksServicesTests:RebootEscrowDataTest */ @RunWith(AndroidJUnit4.class) public class RebootEscrowDataTest { + private RebootEscrowKey mKey; + + @Before + public void generateKey() throws Exception { + mKey = RebootEscrowKey.generate(); + } + private static byte[] getTestSp() { byte[] testSp = new byte[10]; for (int i = 0; i < testSp.length; i++) { @@ -41,30 +47,30 @@ public class RebootEscrowDataTest { @Test(expected = NullPointerException.class) public void fromEntries_failsOnNull() throws Exception { - RebootEscrowData.fromSyntheticPassword((byte) 2, null); + RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, null); } @Test(expected = NullPointerException.class) public void fromEncryptedData_failsOnNullData() throws Exception { byte[] testSp = getTestSp(); - RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword((byte) 2, testSp); - SecretKeySpec key = RebootEscrowData.fromKeyBytes(expected.getKey()); + RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp); + RebootEscrowKey key = RebootEscrowKey.fromKeyBytes(expected.getKey().getKeyBytes()); RebootEscrowData.fromEncryptedData(key, null); } @Test(expected = NullPointerException.class) public void fromEncryptedData_failsOnNullKey() throws Exception { byte[] testSp = getTestSp(); - RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword((byte) 2, testSp); + RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp); RebootEscrowData.fromEncryptedData(null, expected.getBlob()); } @Test public void fromEntries_loopback_success() throws Exception { byte[] testSp = getTestSp(); - RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword((byte) 2, testSp); + RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp); - SecretKeySpec key = RebootEscrowData.fromKeyBytes(expected.getKey()); + RebootEscrowKey key = RebootEscrowKey.fromKeyBytes(expected.getKey().getKeyBytes()); RebootEscrowData actual = RebootEscrowData.fromEncryptedData(key, expected.getBlob()); assertThat(actual.getSpVersion(), is(expected.getSpVersion())); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index 78a5a0b69fff..44d88d2b44d3 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -18,6 +18,7 @@ package com.android.server.locksettings; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_PRIMARY; +import static android.content.pm.UserInfo.FLAG_PROFILE; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -27,6 +28,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -56,7 +58,9 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public class RebootEscrowManagerTests { protected static final int PRIMARY_USER_ID = 0; - protected static final int NONSECURE_USER_ID = 10; + protected static final int WORK_PROFILE_USER_ID = 10; + protected static final int NONSECURE_SECONDARY_USER_ID = 20; + protected static final int SECURE_SECONDARY_USER_ID = 21; private static final byte FAKE_SP_VERSION = 1; private static final byte[] FAKE_AUTH_TOKEN = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -107,10 +111,14 @@ public class RebootEscrowManagerTests { ArrayList<UserInfo> users = new ArrayList<>(); users.add(new UserInfo(PRIMARY_USER_ID, "primary", FLAG_PRIMARY)); - users.add(new UserInfo(NONSECURE_USER_ID, "non-secure", FLAG_FULL)); + users.add(new UserInfo(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE)); + users.add(new UserInfo(NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL)); + users.add(new UserInfo(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL)); when(mUserManager.getUsers()).thenReturn(users); when(mCallbacks.isUserSecure(PRIMARY_USER_ID)).thenReturn(true); - when(mCallbacks.isUserSecure(NONSECURE_USER_ID)).thenReturn(false); + when(mCallbacks.isUserSecure(WORK_PROFILE_USER_ID)).thenReturn(true); + when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false); + when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true); mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mRebootEscrow), mCallbacks, mStorage); } @@ -154,6 +162,30 @@ public class RebootEscrowManagerTests { assertTrue(mService.armRebootEscrowIfNeeded()); verify(mRebootEscrow).storeKey(any()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + } + + @Test + public void armService_MultipleUsers_Success() throws Exception { + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + mService.callToRebootEscrowIfNeeded(SECURE_SECONDARY_USER_ID, FAKE_SP_VERSION, + FAKE_AUTH_TOKEN); + verify(mRebootEscrow, never()).storeKey(any()); + + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mRebootEscrow, times(1)).storeKey(any()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java index d3166b91dc9e..4ae374abb7c2 100644 --- a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java @@ -28,6 +28,7 @@ import android.app.prediction.IPredictionCallback; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Binder; +import android.os.Bundle; import android.os.RemoteException; import com.android.server.LocalServices; @@ -76,6 +77,7 @@ public final class PeopleServiceTest { mPredictionContext = new AppPredictionContext.Builder(mContext) .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) .setPredictedTargetCount(APP_PREDICTION_TARGET_COUNT) + .setExtras(new Bundle()) .build(); } diff --git a/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java new file mode 100644 index 000000000000..7a16d171b475 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java @@ -0,0 +1,169 @@ +/* + * 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.server.people.data; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.provider.CallLog.Calls; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.test.mock.MockContext; +import android.util.ArrayMap; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +@RunWith(JUnit4.class) +public final class CallLogQueryHelperTest { + + private static final String CALL_LOG_AUTHORITY = "call_log"; + private static final String NORMALIZED_PHONE_NUMBER = "+16505551111"; + + private static final String[] CALL_LOG_COLUMNS = new String[] { + Calls.CACHED_NORMALIZED_NUMBER, Calls.DATE, Calls.DURATION, Calls.TYPE }; + + @Mock + private MockContext mContext; + + private MatrixCursor mCursor; + private EventConsumer mEventConsumer; + private CallLogQueryHelper mHelper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mCursor = new MatrixCursor(CALL_LOG_COLUMNS); + + MockContentResolver contentResolver = new MockContentResolver(); + contentResolver.addProvider(CALL_LOG_AUTHORITY, new CallLogContentProvider()); + when(mContext.getContentResolver()).thenReturn(contentResolver); + + mEventConsumer = new EventConsumer(); + mHelper = new CallLogQueryHelper(mContext, mEventConsumer); + } + + @Test + public void testQueryNoCalls() { + assertFalse(mHelper.querySince(50L)); + assertFalse(mEventConsumer.mEventMap.containsKey(NORMALIZED_PHONE_NUMBER)); + } + + @Test + public void testQueryIncomingCall() { + mCursor.addRow(new Object[] { + NORMALIZED_PHONE_NUMBER, /* date= */ 100L, /* duration= */ 30L, + /* type= */ Calls.INCOMING_TYPE }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100L, mHelper.getLastCallTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_CALL_INCOMING, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + assertEquals(30L, events.get(0).getCallDetails().getDurationSeconds()); + } + + @Test + public void testQueryOutgoingCall() { + mCursor.addRow(new Object[] { + NORMALIZED_PHONE_NUMBER, /* date= */ 100L, /* duration= */ 40L, + /* type= */ Calls.OUTGOING_TYPE }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100L, mHelper.getLastCallTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_CALL_OUTGOING, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + assertEquals(40L, events.get(0).getCallDetails().getDurationSeconds()); + } + + @Test + public void testQueryMissedCall() { + mCursor.addRow(new Object[] { + NORMALIZED_PHONE_NUMBER, /* date= */ 100L, /* duration= */ 0L, + /* type= */ Calls.MISSED_TYPE }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100L, mHelper.getLastCallTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_CALL_MISSED, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + assertEquals(0L, events.get(0).getCallDetails().getDurationSeconds()); + } + + @Test + public void testQueryMultipleCalls() { + mCursor.addRow(new Object[] { + NORMALIZED_PHONE_NUMBER, /* date= */ 100L, /* duration= */ 0L, + /* type= */ Calls.MISSED_TYPE }); + mCursor.addRow(new Object[] { + NORMALIZED_PHONE_NUMBER, /* date= */ 110L, /* duration= */ 40L, + /* type= */ Calls.OUTGOING_TYPE }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(110L, mHelper.getLastCallTimestamp()); + assertEquals(2, events.size()); + assertEquals(Event.TYPE_CALL_MISSED, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + assertEquals(Event.TYPE_CALL_OUTGOING, events.get(1).getType()); + assertEquals(110L, events.get(1).getTimestamp()); + assertEquals(40L, events.get(1).getCallDetails().getDurationSeconds()); + } + + private class EventConsumer implements BiConsumer<String, Event> { + + private final Map<String, List<Event>> mEventMap = new ArrayMap<>(); + + @Override + public void accept(String phoneNumber, Event event) { + mEventMap.computeIfAbsent(phoneNumber, key -> new ArrayList<>()).add(event); + } + } + + private class CallLogContentProvider extends MockContentProvider { + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return mCursor; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 9f3d656188e1..62ea425a54a7 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -18,6 +18,8 @@ package com.android.server.people.data; import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -40,14 +42,12 @@ import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; -import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.database.ContentObserver; @@ -58,6 +58,7 @@ import android.os.UserManager; import android.provider.ContactsContract; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; +import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import android.util.Range; @@ -79,6 +80,7 @@ import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; @RunWith(JUnit4.class) public final class DataManagerTest { @@ -90,6 +92,7 @@ public final class DataManagerTest { private static final String TEST_SHORTCUT_ID = "sc"; private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123"; private static final String PHONE_NUMBER = "+1234567890"; + private static final long MILLIS_PER_MINUTE = 1000L * 60L; @Mock private Context mContext; @Mock private ShortcutServiceInternal mShortcutServiceInternal; @@ -97,6 +100,7 @@ public final class DataManagerTest { @Mock private ShortcutManager mShortcutManager; @Mock private UserManager mUserManager; @Mock private TelephonyManager mTelephonyManager; + @Mock private TelecomManager mTelecomManager; @Mock private ContentResolver mContentResolver; @Mock private ScheduledExecutorService mExecutorService; @Mock private ScheduledFuture mScheduledFuture; @@ -117,6 +121,9 @@ public final class DataManagerTest { when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + Context originalContext = getInstrumentation().getTargetContext(); + when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo()); + when(mContext.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(mShortcutManager); when(mContext.getSystemServiceName(ShortcutManager.class)).thenReturn( Context.SHORTCUT_SERVICE); @@ -127,6 +134,11 @@ public final class DataManagerTest { when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager); + when(mContext.getSystemServiceName(TelecomManager.class)).thenReturn( + Context.TELECOM_SERVICE); + when(mTelecomManager.getDefaultDialerPackage(anyInt())).thenReturn(TEST_PKG_NAME); + when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any( TimeUnit.class))).thenReturn(mScheduledFuture); @@ -224,31 +236,6 @@ public final class DataManagerTest { } @Test - public void testGetShareTargets() { - mDataManager.onUserUnlocked(USER_ID_PRIMARY); - - ShortcutInfo shortcut1 = - buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1", buildPerson()); - ShareShortcutInfo shareShortcut1 = - new ShareShortcutInfo(shortcut1, new ComponentName("pkg_1", "activity")); - - ShortcutInfo shortcut2 = - buildShortcutInfo("pkg_2", USER_ID_PRIMARY, "sc_2", buildPerson()); - ShareShortcutInfo shareShortcut2 = - new ShareShortcutInfo(shortcut2, new ComponentName("pkg_2", "activity")); - mDataManager.onShortcutAddedOrUpdated(shortcut2); - - when(mShortcutManager.getShareTargets(any(IntentFilter.class))) - .thenReturn(Arrays.asList(shareShortcut1, shareShortcut2)); - - List<ShareShortcutInfo> shareShortcuts = - mDataManager.getConversationShareTargets(new IntentFilter()); - // Only "sc_2" is stored as a conversation. - assertEquals(1, shareShortcuts.size()); - assertEquals("sc_2", shareShortcuts.get(0).getShortcutInfo().getId()); - } - - @Test public void testReportAppTargetEvent() throws IntentFilter.MalformedMimeTypeException { mDataManager.onUserUnlocked(USER_ID_PRIMARY); ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, @@ -332,7 +319,7 @@ public final class DataManagerTest { events.add(e); UsageEvents usageEvents = new UsageEvents(events, new String[]{}); when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(), - anyBoolean())).thenReturn(usageEvents); + anyBoolean(), anyBoolean())).thenReturn(usageEvents); mDataManager.onUserUnlocked(USER_ID_PRIMARY); @@ -351,6 +338,61 @@ public final class DataManagerTest { assertEquals(1, activeShortcutInvocationTimeSlots.size()); } + @Test + public void testCallLogContentObserver() { + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + buildPerson()); + mDataManager.onShortcutAddedOrUpdated(shortcut); + + ContentObserver contentObserver = mDataManager.getCallLogContentObserverForTesting(); + contentObserver.onChange(false); + long currentTimestamp = System.currentTimeMillis(); + mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER, + new Event(currentTimestamp - MILLIS_PER_MINUTE * 15L, Event.TYPE_CALL_OUTGOING)); + mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER, + new Event(currentTimestamp - MILLIS_PER_MINUTE * 10L, Event.TYPE_CALL_INCOMING)); + mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER, + new Event(currentTimestamp - MILLIS_PER_MINUTE * 5L, Event.TYPE_CALL_MISSED)); + + List<Range<Long>> activeTimeSlots = new ArrayList<>(); + mDataManager.forAllPackages(packageData -> + activeTimeSlots.addAll( + packageData.getEventHistory(TEST_SHORTCUT_ID) + .getEventIndex(Event.CALL_EVENT_TYPES) + .getActiveTimeSlots())); + assertEquals(3, activeTimeSlots.size()); + } + + @Test + public void testMmsSmsContentObserver() { + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + buildPerson()); + mDataManager.onShortcutAddedOrUpdated(shortcut); + mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME); + + ContentObserver contentObserver = mDataManager.getMmsSmsContentObserverForTesting(); + contentObserver.onChange(false); + long currentTimestamp = System.currentTimeMillis(); + Event outgoingSmsEvent = + new Event(currentTimestamp - MILLIS_PER_MINUTE * 10L, Event.TYPE_SMS_OUTGOING); + Event incomingSmsEvent = + new Event(currentTimestamp - MILLIS_PER_MINUTE * 5L, Event.TYPE_SMS_INCOMING); + mInjector.mMmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, outgoingSmsEvent); + mInjector.mSmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, incomingSmsEvent); + + List<Range<Long>> activeTimeSlots = new ArrayList<>(); + mDataManager.forAllPackages(packageData -> + activeTimeSlots.addAll( + packageData.getEventHistory(TEST_SHORTCUT_ID) + .getEventIndex(Event.SMS_EVENT_TYPES) + .getActiveTimeSlots())); + assertEquals(2, activeTimeSlots.size()); + } + private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { LocalServices.removeServiceForTest(clazz); LocalServices.addService(clazz, mock); @@ -428,10 +470,73 @@ public final class DataManagerTest { } } + private class TestCallLogQueryHelper extends CallLogQueryHelper { + + private final BiConsumer<String, Event> mEventConsumer; + + TestCallLogQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + super(context, eventConsumer); + mEventConsumer = eventConsumer; + } + + @Override + boolean querySince(long sinceTime) { + return true; + } + + @Override + long getLastCallTimestamp() { + return 100L; + } + } + + private class TestSmsQueryHelper extends SmsQueryHelper { + + private final BiConsumer<String, Event> mEventConsumer; + + TestSmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + super(context, eventConsumer); + mEventConsumer = eventConsumer; + } + + @Override + boolean querySince(long sinceTime) { + return true; + } + + @Override + long getLastMessageTimestamp() { + return 100L; + } + } + + private class TestMmsQueryHelper extends MmsQueryHelper { + + private final BiConsumer<String, Event> mEventConsumer; + + TestMmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) { + super(context, eventConsumer); + mEventConsumer = eventConsumer; + } + + @Override + boolean querySince(long sinceTime) { + return true; + } + + @Override + long getLastMessageTimestamp() { + return 100L; + } + } + private class TestInjector extends DataManager.Injector { private final TestContactsQueryHelper mContactsQueryHelper = new TestContactsQueryHelper(mContext); + private TestCallLogQueryHelper mCallLogQueryHelper; + private TestMmsQueryHelper mMmsQueryHelper; + private TestSmsQueryHelper mSmsQueryHelper; @Override ScheduledExecutorService createScheduledExecutor() { @@ -444,6 +549,27 @@ public final class DataManagerTest { } @Override + CallLogQueryHelper createCallLogQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + mCallLogQueryHelper = new TestCallLogQueryHelper(context, eventConsumer); + return mCallLogQueryHelper; + } + + @Override + MmsQueryHelper createMmsQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + mMmsQueryHelper = new TestMmsQueryHelper(context, eventConsumer); + return mMmsQueryHelper; + } + + @Override + SmsQueryHelper createSmsQueryHelper(Context context, + BiConsumer<String, Event> eventConsumer) { + mSmsQueryHelper = new TestSmsQueryHelper(context, eventConsumer); + return mSmsQueryHelper; + } + + @Override int getCallingUserId() { return mCallingUserId; } diff --git a/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java new file mode 100644 index 000000000000..7730890e1486 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java @@ -0,0 +1,174 @@ +/* + * 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.server.people.data; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.provider.Telephony.BaseMmsColumns; +import android.provider.Telephony.Mms; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.test.mock.MockContext; +import android.util.ArrayMap; + +import com.google.android.mms.pdu.PduHeaders; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +@RunWith(JUnit4.class) +public final class MmsQueryHelperTest { + + private static final String MMS_AUTHORITY = "mms"; + private static final String PHONE_NUMBER = "650-555-1111"; + private static final String NORMALIZED_PHONE_NUMBER = "+16505551111"; + private static final String OWN_PHONE_NUMBER = "650-555-9999"; + + private static final String[] MMS_COLUMNS = new String[] { Mms._ID, Mms.DATE, Mms.MESSAGE_BOX }; + private static final String[] ADDR_COLUMNS = new String[] { Mms.Addr.ADDRESS, Mms.Addr.TYPE }; + + @Mock + private MockContext mContext; + + private MatrixCursor mMmsCursor; + private final List<MatrixCursor> mAddrCursors = new ArrayList<>(); + private EventConsumer mEventConsumer; + private MmsQueryHelper mHelper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mMmsCursor = new MatrixCursor(MMS_COLUMNS); + mAddrCursors.add(new MatrixCursor(ADDR_COLUMNS)); + mAddrCursors.add(new MatrixCursor(ADDR_COLUMNS)); + + MockContentResolver contentResolver = new MockContentResolver(); + contentResolver.addProvider(MMS_AUTHORITY, new MmsContentProvider()); + when(mContext.getContentResolver()).thenReturn(contentResolver); + + mEventConsumer = new EventConsumer(); + mHelper = new MmsQueryHelper(mContext, mEventConsumer); + } + + @Test + public void testQueryNoMessages() { + assertFalse(mHelper.querySince(50_000L)); + assertFalse(mEventConsumer.mEventMap.containsKey(NORMALIZED_PHONE_NUMBER)); + } + + @Test + public void testQueryIncomingMessage() { + mMmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* msgBox= */ BaseMmsColumns.MESSAGE_BOX_INBOX }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ PHONE_NUMBER, /* type= */ PduHeaders.FROM }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ OWN_PHONE_NUMBER, /* type= */ PduHeaders.TO }); + + assertTrue(mHelper.querySince(50_000L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100_000L, mHelper.getLastMessageTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_SMS_INCOMING, events.get(0).getType()); + assertEquals(100_000L, events.get(0).getTimestamp()); + } + + @Test + public void testQueryOutgoingMessage() { + mMmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* msgBox= */ BaseMmsColumns.MESSAGE_BOX_SENT }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ OWN_PHONE_NUMBER, /* type= */ PduHeaders.FROM }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ PHONE_NUMBER, /* type= */ PduHeaders.TO }); + + assertTrue(mHelper.querySince(50_000L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100_000L, mHelper.getLastMessageTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_SMS_OUTGOING, events.get(0).getType()); + assertEquals(100_000L, events.get(0).getTimestamp()); + } + + @Test + public void testQueryMultipleMessages() { + mMmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* msgBox= */ BaseMmsColumns.MESSAGE_BOX_SENT }); + mMmsCursor.addRow(new Object[] { + /* id= */ 1, /* date= */ 110L, /* msgBox= */ BaseMmsColumns.MESSAGE_BOX_INBOX }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ OWN_PHONE_NUMBER, /* type= */ PduHeaders.FROM }); + mAddrCursors.get(0).addRow(new Object[] { + /* address= */ PHONE_NUMBER, /* type= */ PduHeaders.TO }); + mAddrCursors.get(1).addRow(new Object[] { + /* address= */ PHONE_NUMBER, /* type= */ PduHeaders.FROM }); + mAddrCursors.get(1).addRow(new Object[] { + /* address= */ OWN_PHONE_NUMBER, /* type= */ PduHeaders.TO }); + + assertTrue(mHelper.querySince(50_000L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(110_000L, mHelper.getLastMessageTimestamp()); + assertEquals(2, events.size()); + assertEquals(Event.TYPE_SMS_OUTGOING, events.get(0).getType()); + assertEquals(100_000L, events.get(0).getTimestamp()); + assertEquals(Event.TYPE_SMS_INCOMING, events.get(1).getType()); + assertEquals(110_000L, events.get(1).getTimestamp()); + } + + private class EventConsumer implements BiConsumer<String, Event> { + + private final Map<String, List<Event>> mEventMap = new ArrayMap<>(); + + @Override + public void accept(String phoneNumber, Event event) { + mEventMap.computeIfAbsent(phoneNumber, key -> new ArrayList<>()).add(event); + } + } + + private class MmsContentProvider extends MockContentProvider { + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + List<String> segments = uri.getPathSegments(); + if (segments.size() == 2 && "addr".equals(segments.get(1))) { + int messageId = Integer.valueOf(segments.get(0)); + return mAddrCursors.get(messageId); + } + return mMmsCursor; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java index 1b80d6fc3a2d..ec4789ad0cdf 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java @@ -16,7 +16,6 @@ package com.android.server.people.data; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -46,12 +45,15 @@ public final class PackageDataTest { private Event mE2; private Event mE3; private Event mE4; + private boolean mIsDefaultDialer; + private boolean mIsDefaultSmsApp; private PackageData mPackageData; @Before public void setUp() { - mPackageData = new PackageData(PACKAGE_NAME, USER_ID); + mPackageData = new PackageData( + PACKAGE_NAME, USER_ID, pkg -> mIsDefaultDialer, pkg -> mIsDefaultSmsApp); ConversationInfo conversationInfo = new ConversationInfo.Builder() .setShortcutId(SHORTCUT_ID) .setLocusId(LOCUS_ID) @@ -83,8 +85,8 @@ public final class PackageDataTest { @Test public void testGetEventHistoryDefaultDialerAndSmsApp() { - mPackageData.setIsDefaultDialer(true); - mPackageData.setIsDefaultSmsApp(true); + mIsDefaultDialer = true; + mIsDefaultSmsApp = true; EventStore eventStore = mPackageData.getEventStore(); eventStore.getOrCreateShortcutEventHistory(SHORTCUT_ID).addEvent(mE1); eventStore.getOrCreateCallEventHistory(PHONE_NUMBER).addEvent(mE3); diff --git a/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java new file mode 100644 index 000000000000..5cb8cb4fe9f1 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java @@ -0,0 +1,151 @@ +/* + * 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.server.people.data; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.provider.Telephony.Sms; +import android.provider.Telephony.TextBasedSmsColumns; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.test.mock.MockContext; +import android.util.ArrayMap; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +@RunWith(JUnit4.class) +public final class SmsQueryHelperTest { + + private static final String SMS_AUTHORITY = "sms"; + private static final String PHONE_NUMBER = "650-555-1111"; + private static final String NORMALIZED_PHONE_NUMBER = "+16505551111"; + + private static final String[] SMS_COLUMNS = new String[] { + Sms._ID, Sms.DATE, Sms.TYPE, Sms.ADDRESS }; + + @Mock + private MockContext mContext; + + private MatrixCursor mSmsCursor; + private EventConsumer mEventConsumer; + private SmsQueryHelper mHelper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mSmsCursor = new MatrixCursor(SMS_COLUMNS); + + MockContentResolver contentResolver = new MockContentResolver(); + contentResolver.addProvider(SMS_AUTHORITY, new SmsContentProvider()); + when(mContext.getContentResolver()).thenReturn(contentResolver); + + mEventConsumer = new EventConsumer(); + mHelper = new SmsQueryHelper(mContext, mEventConsumer); + } + + @Test + public void testQueryNoMessages() { + assertFalse(mHelper.querySince(50_000L)); + assertFalse(mEventConsumer.mEventMap.containsKey(NORMALIZED_PHONE_NUMBER)); + } + + @Test + public void testQueryIncomingMessage() { + mSmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* type= */ TextBasedSmsColumns.MESSAGE_TYPE_INBOX, + /* address= */ PHONE_NUMBER }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100L, mHelper.getLastMessageTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_SMS_INCOMING, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + } + + @Test + public void testQueryOutgoingMessage() { + mSmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* type= */ TextBasedSmsColumns.MESSAGE_TYPE_SENT, + /* address= */ PHONE_NUMBER }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(100L, mHelper.getLastMessageTimestamp()); + assertEquals(1, events.size()); + assertEquals(Event.TYPE_SMS_OUTGOING, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + } + + @Test + public void testQueryMultipleMessages() { + mSmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 100L, /* type= */ TextBasedSmsColumns.MESSAGE_TYPE_SENT, + /* address= */ PHONE_NUMBER }); + mSmsCursor.addRow(new Object[] { + /* id= */ 0, /* date= */ 110L, /* type= */ TextBasedSmsColumns.MESSAGE_TYPE_INBOX, + /* address= */ PHONE_NUMBER }); + + assertTrue(mHelper.querySince(50L)); + List<Event> events = mEventConsumer.mEventMap.get(NORMALIZED_PHONE_NUMBER); + + assertEquals(110L, mHelper.getLastMessageTimestamp()); + assertEquals(2, events.size()); + assertEquals(Event.TYPE_SMS_OUTGOING, events.get(0).getType()); + assertEquals(100L, events.get(0).getTimestamp()); + assertEquals(Event.TYPE_SMS_INCOMING, events.get(1).getType()); + assertEquals(110L, events.get(1).getTimestamp()); + } + + private class EventConsumer implements BiConsumer<String, Event> { + + private final Map<String, List<Event>> mEventMap = new ArrayMap<>(); + + @Override + public void accept(String phoneNumber, Event event) { + mEventMap.computeIfAbsent(phoneNumber, key -> new ArrayList<>()).add(event); + } + } + + private class SmsContentProvider extends MockContentProvider { + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return mSmsCursor; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java new file mode 100644 index 000000000000..808906e3a06a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java @@ -0,0 +1,137 @@ +/* + * 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.server.people.prediction; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.prediction.AppPredictionContext; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager.ShareShortcutInfo; +import android.os.Bundle; +import android.os.UserHandle; + +import com.android.server.people.data.ConversationInfo; +import com.android.server.people.data.DataManager; +import com.android.server.people.data.EventHistory; +import com.android.server.people.data.PackageData; +import com.android.server.people.prediction.ShareTargetPredictor.ShareTarget; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(JUnit4.class) +public final class ShareTargetPredictorTest { + + private static final String UI_SURFACE_SHARE = "share"; + private static final int NUM_PREDICTED_TARGETS = 5; + private static final int USER_ID = 0; + private static final String PACKAGE_1 = "pkg1"; + private static final String CLASS_1 = "cls1"; + private static final String PACKAGE_2 = "pkg2"; + private static final String CLASS_2 = "cls2"; + + @Mock private Context mContext; + @Mock private DataManager mDataManager; + @Mock private PackageData mPackageData1; + @Mock private PackageData mPackageData2; + + private List<ShareShortcutInfo> mShareShortcuts = new ArrayList<>(); + + private ShareTargetPredictor mPredictor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mDataManager.getShareShortcuts(any())).thenReturn(mShareShortcuts); + when(mDataManager.getPackage(PACKAGE_1, USER_ID)).thenReturn(mPackageData1); + when(mDataManager.getPackage(PACKAGE_2, USER_ID)).thenReturn(mPackageData2); + + AppPredictionContext predictionContext = new AppPredictionContext.Builder(mContext) + .setUiSurface(UI_SURFACE_SHARE) + .setPredictedTargetCount(NUM_PREDICTED_TARGETS) + .setExtras(new Bundle()) + .build(); + mPredictor = new ShareTargetPredictor(predictionContext, targets -> { }, mDataManager); + } + + @Test + public void testGetShareTargets() { + mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1")); + mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2")); + mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3")); + mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4")); + + when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class)); + when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class)); + when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class)); + // "sc4" does not have a ConversationInfo. + + when(mPackageData1.getEventHistory(anyString())).thenReturn(mock(EventHistory.class)); + when(mPackageData2.getEventHistory(anyString())).thenReturn(mock(EventHistory.class)); + + List<ShareTarget> shareTargets = mPredictor.getShareTargets(); + + assertEquals(4, shareTargets.size()); + + assertEquals("sc1", shareTargets.get(0).getShareShortcutInfo().getShortcutInfo().getId()); + assertNotNull(shareTargets.get(0).getConversationData()); + + assertEquals("sc2", shareTargets.get(1).getShareShortcutInfo().getShortcutInfo().getId()); + assertNotNull(shareTargets.get(1).getConversationData()); + + assertEquals("sc3", shareTargets.get(2).getShareShortcutInfo().getShortcutInfo().getId()); + assertNotNull(shareTargets.get(2).getConversationData()); + + assertEquals("sc4", shareTargets.get(3).getShareShortcutInfo().getShortcutInfo().getId()); + assertNull(shareTargets.get(3).getConversationData()); + } + + private ShareShortcutInfo buildShareShortcut( + String packageName, String className, String shortcutId) { + ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId); + ComponentName componentName = new ComponentName(packageName, className); + return new ShareShortcutInfo(shortcutInfo, componentName); + } + + private ShortcutInfo buildShortcut(String packageName, String shortcutId) { + Context mockContext = mock(Context.class); + when(mockContext.getPackageName()).thenReturn(packageName); + when(mockContext.getUserId()).thenReturn(USER_ID); + when(mockContext.getUser()).thenReturn(UserHandle.of(USER_ID)); + ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mockContext, shortcutId) + .setShortLabel(shortcutId) + .setIntent(new Intent("TestIntent")); + return builder.build(); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java index 71390dbbe4a3..0f5489575ee0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static org.junit.Assert.assertFalse; @@ -69,8 +70,10 @@ public class AnimatingActivityRegistryTest extends WindowTestsBase { final AnimatingActivityRegistry registry = activity1.getStack().getAnimatingActivityRegistry(); - activity1.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */); - activity2.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */); + activity1.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); + activity2.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); assertTrue(activity1.isAnimating(TRANSITION)); assertTrue(activity2.isAnimating(TRANSITION)); @@ -91,8 +94,10 @@ public class AnimatingActivityRegistryTest extends WindowTestsBase { final AnimatingActivityRegistry registry = window1.getStack().getAnimatingActivityRegistry(); - window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); - window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */); + window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); + window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); assertTrue(window1.isAnimating(TRANSITION)); assertTrue(window2.isAnimating(TRANSITION)); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java index b0f3b42271de..6e78a271458a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.google.common.truth.Truth.assertThat; @@ -70,7 +71,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { public void clipAfterAnim_boundsLayerIsCreated() { mActivity.mNeedsAnimationBoundsLayer = true; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()), eq(mActivity.mSurfaceAnimator.mLeash)); verify(mTransaction).reparent(eq(mActivity.mSurfaceAnimator.mLeash), @@ -82,7 +84,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { mActivity.mNeedsAnimationBoundsLayer = true; mActivity.mNeedsZBoost = true; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); verify(mTransaction).setLayer(eq(mActivity.mAnimationBoundsLayer), intThat(layer -> layer >= ActivityRecord.Z_BOOST_BASE)); } @@ -91,15 +94,18 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { @FlakyTest(bugId = 131005232) public void clipAfterAnim_boundsLayerIsDestroyed() { mActivity.mNeedsAnimationBoundsLayer = true; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash; final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer; final ArgumentCaptor<SurfaceAnimator.OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( SurfaceAnimator.OnAnimationFinishedCallback.class); - verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), + callbackCaptor.capture()); - callbackCaptor.getValue().onAnimationFinished(mSpec); + callbackCaptor.getValue().onAnimationFinished( + ANIMATION_TYPE_APP_TRANSITION, mSpec); verify(mTransaction).remove(eq(leash)); verify(mTransaction).remove(eq(animationBoundsLayer)); assertThat(mActivity.mNeedsAnimationBoundsLayer).isFalse(); @@ -108,7 +114,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { @Test public void clipAfterAnimCancelled_boundsLayerIsDestroyed() { mActivity.mNeedsAnimationBoundsLayer = true; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash; final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer; @@ -123,7 +130,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { public void clipNoneAnim_boundsLayerIsNotCreated() { mActivity.mNeedsAnimationBoundsLayer = false; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()), eq(mActivity.mSurfaceAnimator.mLeash)); assertThat(mActivity.mAnimationBoundsLayer).isNull(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index 7344fa42016c..77ceeedae1ac 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -22,11 +22,13 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; @@ -37,6 +39,9 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; +import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -114,11 +119,11 @@ public class DimmerTests extends WindowTestsBase { private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter { @Override public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, - @Nullable Runnable animationFinishedCallback) { - surfaceAnimator.mStaticAnimationFinishedCallback.run(); + AnimationAdapter anim, boolean hidden, @AnimationType int type, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim); if (animationFinishedCallback != null) { - animationFinishedCallback.run(); + animationFinishedCallback.onAnimationFinished(type, anim); } } } @@ -224,7 +229,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), - isNull()); + eq(ANIMATION_TYPE_DIMMER), isNull()); verify(mHost.getPendingTransaction()).remove(dimLayer); } @@ -282,7 +287,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), - isNull()); + eq(ANIMATION_TYPE_DIMMER), isNull()); verify(mTransaction).remove(dimLayer); } 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 5ba676d1c544..9dbaa4c9ca82 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -73,6 +73,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.PrintWriter; +import java.io.StringWriter; + /** * Tests for the {@link DisplayPolicy} class. * @@ -122,9 +125,13 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } private void updateDisplayFrames() { + mFrames = createDisplayFrames(); + } + + private DisplayFrames createDisplayFrames() { final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation, mHasDisplayCutout); - mFrames = new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second); + return new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second); } @Test @@ -824,6 +831,49 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper())); } + /** + * Verify that {@link DisplayPolicy#simulateLayoutDisplay} outputs the same display frames as + * {@link DisplayPolicy#beginLayoutLw}. + */ + @Test + public void testSimulateLayoutDisplay() { + assertSimulateLayoutSameDisplayFrames(); + setRotation(ROTATION_90); + assertSimulateLayoutSameDisplayFrames(); + addDisplayCutout(); + assertSimulateLayoutSameDisplayFrames(); + } + + private void assertSimulateLayoutSameDisplayFrames() { + final int uiMode = 0; + final String prefix = ""; + final InsetsState simulatedInsetsState = new InsetsState(); + final DisplayFrames simulatedDisplayFrames = createDisplayFrames(); + mDisplayContent.mDisplayFrames = mFrames; + mDisplayPolicy.beginLayoutLw(mFrames, uiMode); + mDisplayContent.getInsetsStateController().onPostLayout(); + mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode); + + final StringWriter realFramesDump = new StringWriter(); + mFrames.dump(prefix, new PrintWriter(realFramesDump)); + final StringWriter simulatedFramesDump = new StringWriter(); + simulatedDisplayFrames.dump(prefix, new PrintWriter(simulatedFramesDump)); + + assertEquals(realFramesDump.toString(), simulatedFramesDump.toString()); + + final StringWriter realInsetsDump = new StringWriter(); + final InsetsState realInsetsState = new InsetsState( + mDisplayContent.getInsetsStateController().getRawInsetsState()); + // Exclude comparing IME insets because currently the simulated layout only focuses on the + // insets from status bar and navigation bar. + realInsetsState.removeSource(InsetsState.ITYPE_IME); + realInsetsState.dump(prefix, new PrintWriter(realInsetsDump)); + final StringWriter simulatedInsetsDump = new StringWriter(); + simulatedInsetsState.dump(prefix, new PrintWriter(simulatedInsetsDump)); + + assertEquals(realInsetsDump.toString(), simulatedInsetsDump.toString()); + } + @Test public void forceShowSystemBars_clearsSystemUIFlags() { mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN; diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 945928d1b967..7753a32d8ca0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -37,6 +37,7 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -103,14 +104,15 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); AnimationAdapter adapter = mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */); - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS, + mFinishedCallback); // Remove the app window so that the animation target can not be created activity.removeImmediately(); mController.startAnimation(); // Verify that the finish callback to reparent the leash is called - verify(mFinishedCallback).onAnimationFinished(eq(adapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_RECENTS), eq(adapter)); // Verify the animation canceled callback to the app was made verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */); verifyNoMoreInteractionsExceptAsBinder(mMockRunner); @@ -122,7 +124,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); AnimationAdapter adapter = mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */); - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS, + mFinishedCallback); // Remove the app window so that the animation target can not be created activity.removeImmediately(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java index a23425f2510c..be2559719438 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -108,7 +110,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase { overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID; overrideWindow.mActivityRecord.mSurfaceAnimator.startAnimation( overrideWindow.getPendingTransaction(), mock(AnimationAdapter.class), - false /* hidden */); + false /* hidden */, ANIMATION_TYPE_APP_TRANSITION); mPolicy.addNonHighRefreshRatePackage("com.android.test"); assertEquals(0, mPolicy.getPreferredModeId(overrideWindow)); } @@ -124,7 +126,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase { cameraUsingWindow.mActivityRecord.mSurfaceAnimator.startAnimation( cameraUsingWindow.getPendingTransaction(), mock(AnimationAdapter.class), - false /* hidden */); + false /* hidden */, ANIMATION_TYPE_APP_TRANSITION); assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow)); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 1a575962b961..3a724a140ffb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -25,6 +25,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -97,7 +99,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { try { final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = @@ -122,7 +125,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50); finishedCaptor.getValue().onAnimationFinished(); - verify(mFinishedCallback).onAnimationFinished(eq(adapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), + eq(adapter)); } finally { mDisplayContent.mOpeningApps.clear(); } @@ -133,7 +137,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); adapter.onAnimationCancelled(mMockLeash); @@ -146,14 +151,16 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mClock.fastForward(2500); mHandler.timeAdvance(); verify(mMockRunner).onAnimationCancelled(); - verify(mFinishedCallback).onAnimationFinished(eq(adapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), + eq(adapter)); } @Test @@ -164,7 +171,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { "testWin"); final AnimationAdapter adapter = mController.createRemoteAnimationRecord( win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mClock.fastForward(2500); @@ -176,7 +184,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mHandler.timeAdvance(); verify(mMockRunner).onAnimationCancelled(); - verify(mFinishedCallback).onAnimationFinished(eq(adapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), + eq(adapter)); } finally { mWm.setAnimationScale(2, 1.0f); } @@ -205,7 +214,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { new Point(50, 100), new Rect(50, 100, 150, 150), null); final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win2.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = @@ -225,11 +235,13 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); win.mActivityRecord.removeImmediately(); mController.goodToGo(); verifyNoMoreInteractionsExceptAsBinder(mMockRunner); - verify(mFinishedCallback).onAnimationFinished(eq(adapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), + eq(adapter)); } @Test @@ -242,9 +254,10 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { new Rect(0, 0, 200, 200)); assertNotNull(record.mThumbnailAdapter); ((AnimationAdapter) record.mAdapter) - .startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, + mFinishedCallback); ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash, - mMockTransaction, mThumbnailFinishedCallback); + mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback); mController.goodToGo(); mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = @@ -272,8 +285,10 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0); finishedCaptor.getValue().onAnimationFinished(); - verify(mFinishedCallback).onAnimationFinished(eq(record.mAdapter)); - verify(mThumbnailFinishedCallback).onAnimationFinished(eq(record.mThumbnailAdapter)); + verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION), + eq(record.mAdapter)); + verify(mThumbnailFinishedCallback).onAnimationFinished( + eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter)); } finally { mDisplayContent.mChangingApps.clear(); } @@ -290,7 +305,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { try { final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = @@ -318,7 +334,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { try { final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter; - adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); + adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION, + mFinishedCallback); mController.goodToGo(); mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index 2894241356f7..552c476613b2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -22,6 +22,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,6 +41,7 @@ import android.view.SurfaceSession; import androidx.test.filters.SmallTest; import com.android.server.wm.SurfaceAnimator.Animatable; +import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import org.junit.After; @@ -89,25 +92,30 @@ public class SurfaceAnimatorTest extends WindowTestsBase { @Test public void testRunAnimation() { - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_RECENTS); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); assertAnimating(mAnimatable); verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash)); - verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_RECENTS), + callbackCaptor.capture()); - callbackCaptor.getValue().onAnimationFinished(mSpec); + callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_RECENTS, mSpec); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_RECENTS, mAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(mAnimatable.mLeash)); // TODO: Verify reparenting once we use mPendingTransaction to reparent it back } @Test public void testOverrideAnimation() { - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); final SurfaceControl firstLeash = mAnimatable.mLeash; - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); verify(mTransaction).remove(eq(firstLeash)); assertFalse(mAnimatable.mFinishedCallbackCalled); @@ -115,34 +123,40 @@ public class SurfaceAnimatorTest extends WindowTestsBase { final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); assertAnimating(mAnimatable); - verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), + callbackCaptor.capture()); // First animation was finished, but this shouldn't cancel the second animation - callbackCaptor.getValue().onAnimationFinished(mSpec); + callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec); assertTrue(mAnimatable.mSurfaceAnimator.isAnimating()); // Second animation was finished - verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture()); - callbackCaptor.getValue().onAnimationFinished(mSpec2); + verify(mSpec2).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), + callbackCaptor.capture()); + callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec2); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType); } @Test public void testCancelAnimation() { - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); assertAnimating(mAnimatable); mAnimatable.mSurfaceAnimator.cancelAnimation(); assertNotAnimating(mAnimatable); verify(mSpec).onAnimationCancelled(any()); assertTrue(mAnimatable.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(mAnimatable.mLeash)); } @Test public void testCancelWithNullFinishCallbackAnimation() { SurfaceAnimator animator = new SurfaceAnimator(mAnimatable, null, mWm); - animator.startAnimation(mTransaction, mSpec, true /* hidden */); + animator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); assertTrue(animator.isAnimating()); assertNotNull(animator.getAnimation()); animator.cancelAnimation(); @@ -155,32 +169,37 @@ public class SurfaceAnimatorTest extends WindowTestsBase { @Test public void testDelayingAnimationStart() { mAnimatable.mSurfaceAnimator.startDelayingAnimationStart(); - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); verifyZeroInteractions(mSpec); assertAnimating(mAnimatable); assertTrue(mAnimatable.mSurfaceAnimator.isAnimationStartDelayed()); mAnimatable.mSurfaceAnimator.endDelayingAnimationStart(); - verify(mSpec).startAnimation(any(), any(), any()); + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), any()); } @Test public void testDelayingAnimationStartAndCancelled() { mAnimatable.mSurfaceAnimator.startDelayingAnimationStart(); - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); mAnimatable.mSurfaceAnimator.cancelAnimation(); verifyZeroInteractions(mSpec); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(mAnimatable.mLeash)); } @Test public void testTransferAnimation() { - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); - verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); + verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), + callbackCaptor.capture()); final SurfaceControl leash = mAnimatable.mLeash; mAnimatable2.mSurfaceAnimator.transferAnimation(mAnimatable.mSurfaceAnimator); @@ -188,15 +207,17 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertAnimating(mAnimatable2); assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash); verify(mTransaction, never()).remove(eq(leash)); - callbackCaptor.getValue().onAnimationFinished(mSpec); + callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec); assertNotAnimating(mAnimatable2); assertTrue(mAnimatable2.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(leash)); } @Test public void testOnAnimationLeashLostWhenAnimatableParentSurfaceControlNull() { - mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); + mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, + ANIMATION_TYPE_APP_TRANSITION); spyOn(mAnimatable); // Verify onAnimationLeashLost will be called even animatable's parent surface control lost. @@ -215,13 +236,14 @@ public class SurfaceAnimatorTest extends WindowTestsBase { final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec); // Finish the animation but then make sure we are deferring. - onFinishedCallback.onAnimationFinished(mSpec); + onFinishedCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec); assertAnimating(mDeferFinishAnimatable); // Now end defer finishing. mDeferFinishAnimatable.mEndDeferFinishCallback.run(); assertNotAnimating(mAnimatable2); assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled); + assertEquals(ANIMATION_TYPE_APP_TRANSITION, mDeferFinishAnimatable.mFinishedAnimationType); verify(mTransaction).remove(eq(mDeferFinishAnimatable.mLeash)); } @@ -229,7 +251,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { public void testDeferFinishDoNotFinishNextAnimation() { // Start the first animation. final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec); - onFinishedCallback.onAnimationFinished(mSpec); + onFinishedCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec); // The callback is the resetAndInvokeFinish in {@link SurfaceAnimator#getFinishedCallback}. final Runnable firstDeferFinishCallback = mDeferFinishAnimatable.mEndDeferFinishCallback; @@ -247,11 +269,12 @@ public class SurfaceAnimatorTest extends WindowTestsBase { private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) { mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim, - true /* hidden */); + true /* hidden */, ANIMATION_TYPE_APP_TRANSITION); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); assertAnimating(mDeferFinishAnimatable); - verify(anim).startAnimation(any(), any(), callbackCaptor.capture()); + verify(anim).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), + callbackCaptor.capture()); return callbackCaptor.getValue(); } @@ -274,6 +297,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { final SurfaceAnimator mSurfaceAnimator; SurfaceControl mLeash; boolean mFinishedCallbackCalled; + @AnimationType int mFinishedAnimationType; MyAnimatable(WindowManagerService wm, SurfaceSession session, Transaction transaction) { mSession = session; @@ -343,7 +367,11 @@ public class SurfaceAnimatorTest extends WindowTestsBase { return 1; } - private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true; + private final SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback = ( + type, anim) -> { + mFinishedCallbackCalled = true; + mFinishedAnimationType = type; + }; } private static class DeferFinishAnimatable extends MyAnimatable { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 05d048d360ea..4a87701e3c4b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -34,6 +34,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -61,6 +62,8 @@ import android.view.SurfaceSession; import androidx.test.filters.SmallTest; +import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; + import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -829,7 +832,8 @@ public class WindowContainerTests extends WindowTestsBase { wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter); spyOn(wc); doReturn(true).when(wc).okToAnimate(); - final Runnable onAnimationFinishedCallback = mock(Runnable.class); + final OnAnimationFinishedCallback onAnimationFinishedCallback = + mock(OnAnimationFinishedCallback.class); // Make sure animating state is as expected after applied animation. assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false, @@ -837,16 +841,18 @@ public class WindowContainerTests extends WindowTestsBase { assertEquals(wc.getTopMostActivity(), act); assertTrue(wc.isAnimating()); assertTrue(act.isAnimating(PARENTS)); - verify(onAnimationFinishedCallback, times(0)).run(); + verify(onAnimationFinishedCallback, times(0)).onAnimationFinished( + eq(ANIMATION_TYPE_APP_TRANSITION), any()); // Make sure animation finish callback will be received and reset animating state after // animation finish. wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_TASK_OPEN, act, mDisplayContent.mOpeningApps); - verify(wc).onAnimationFinished(); + verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any()); assertFalse(wc.isAnimating()); assertFalse(act.isAnimating(PARENTS)); - verify(onAnimationFinishedCallback, times(1)).run(); + verify(onAnimationFinishedCallback, times(1)).onAnimationFinished( + eq(ANIMATION_TYPE_APP_TRANSITION), any()); } /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 14852d0f4161..48b6e2aaad5c 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -2117,9 +2117,9 @@ public class UsageStatsService extends SystemService implements @Override public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime, - boolean shouldObfuscateInstantApps) { + boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents) { return UsageStatsService.this.queryEvents( - userId, beginTime, endTime, shouldObfuscateInstantApps, false); + userId, beginTime, endTime, obfuscateInstantApps, hideShortcutInvocationEvents); } @Override diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java index 9baa66fcd87e..92423a2f2218 100644 --- a/telephony/java/android/telephony/BarringInfo.java +++ b/telephony/java/android/telephony/BarringInfo.java @@ -62,38 +62,38 @@ public final class BarringInfo implements Parcelable { /* Applicabe to UTRAN */ /** Barring indicator for circuit-switched service; applicable to UTRAN */ public static final int BARRING_SERVICE_TYPE_CS_SERVICE = - android.hardware.radio.V1_5.BarringServiceType.CS_SERVICE; + android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_SERVICE; /** Barring indicator for packet-switched service; applicable to UTRAN */ public static final int BARRING_SERVICE_TYPE_PS_SERVICE = - android.hardware.radio.V1_5.BarringServiceType.PS_SERVICE; + android.hardware.radio.V1_5.BarringInfo.ServiceType.PS_SERVICE; /** Barring indicator for circuit-switched voice service; applicable to UTRAN */ public static final int BARRING_SERVICE_TYPE_CS_VOICE = - android.hardware.radio.V1_5.BarringServiceType.CS_VOICE; + android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_VOICE; /* Applicable to EUTRAN, NGRAN */ /** Barring indicator for mobile-originated signalling; applicable to EUTRAN and NGRAN */ public static final int BARRING_SERVICE_TYPE_MO_SIGNALLING = - android.hardware.radio.V1_5.BarringServiceType.MO_SIGNALLING; + android.hardware.radio.V1_5.BarringInfo.ServiceType.MO_SIGNALLING; /** Barring indicator for mobile-originated data traffic; applicable to EUTRAN and NGRAN */ public static final int BARRING_SERVICE_TYPE_MO_DATA = - android.hardware.radio.V1_5.BarringServiceType.MO_DATA; + android.hardware.radio.V1_5.BarringInfo.ServiceType.MO_DATA; /** Barring indicator for circuit-switched fallback for voice; applicable to EUTRAN and NGRAN */ public static final int BARRING_SERVICE_TYPE_CS_FALLBACK = - android.hardware.radio.V1_5.BarringServiceType.CS_FALLBACK; + android.hardware.radio.V1_5.BarringInfo.ServiceType.CS_FALLBACK; /** Barring indicator for MMTEL (IMS) voice; applicable to EUTRAN and NGRAN */ public static final int BARRING_SERVICE_TYPE_MMTEL_VOICE = - android.hardware.radio.V1_5.BarringServiceType.MMTEL_VOICE; + android.hardware.radio.V1_5.BarringInfo.ServiceType.MMTEL_VOICE; /** Barring indicator for MMTEL (IMS) video; applicable to EUTRAN and NGRAN */ public static final int BARRING_SERVICE_TYPE_MMTEL_VIDEO = - android.hardware.radio.V1_5.BarringServiceType.MMTEL_VIDEO; + android.hardware.radio.V1_5.BarringInfo.ServiceType.MMTEL_VIDEO; /* Applicable to UTRAN, EUTRAN, NGRAN */ /** Barring indicator for emergency services; applicable to UTRAN, EUTRAN, and NGRAN */ public static final int BARRING_SERVICE_TYPE_EMERGENCY = - android.hardware.radio.V1_5.BarringServiceType.EMERGENCY; + android.hardware.radio.V1_5.BarringInfo.ServiceType.EMERGENCY; /** Barring indicator for SMS sending; applicable to UTRAN, EUTRAN, and NGRAN */ public static final int BARRING_SERVICE_TYPE_SMS = - android.hardware.radio.V1_5.BarringServiceType.SMS; + android.hardware.radio.V1_5.BarringInfo.ServiceType.SMS; //TODO: add barring constants for Operator-Specific barring codes @@ -112,13 +112,14 @@ public final class BarringInfo implements Parcelable { public @interface BarringType {} /** Barring is inactive */ - public static final int BARRING_TYPE_NONE = android.hardware.radio.V1_5.BarringType.NONE; + public static final int BARRING_TYPE_NONE = + android.hardware.radio.V1_5.BarringInfo.BarringType.NONE; /** The service is barred */ public static final int BARRING_TYPE_UNCONDITIONAL = - android.hardware.radio.V1_5.BarringType.UNCONDITIONAL; + android.hardware.radio.V1_5.BarringInfo.BarringType.UNCONDITIONAL; /** The service may be barred based on additional factors */ public static final int BARRING_TYPE_CONDITIONAL = - android.hardware.radio.V1_5.BarringType.CONDITIONAL; + android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL; /** If a modem does not report barring info, then the barring type will be UNKNOWN */ public static final int BARRING_TYPE_UNKNOWN = -1; @@ -277,27 +278,29 @@ public final class BarringInfo implements Parcelable { SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>(); for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) { - if (halBarringInfo.type == android.hardware.radio.V1_5.BarringType.CONDITIONAL) { - if (halBarringInfo.typeSpecificInfo.getDiscriminator() - != android.hardware.radio.V1_5.BarringTypeSpecificInfo - .hidl_discriminator.conditionalBarringInfo) { + if (halBarringInfo.barringType + == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) { + if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator() + != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo + .hidl_discriminator.conditional) { // this is an error case where the barring info is conditional but the // conditional barring fields weren't included continue; } - android.hardware.radio.V1_5.ConditionalBarringInfo conditionalInfo = - halBarringInfo.typeSpecificInfo.conditionalBarringInfo(); + android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo + .Conditional conditionalInfo = + halBarringInfo.barringTypeSpecificInfo.conditional(); serviceInfos.put( - halBarringInfo.service, new BarringServiceInfo( - halBarringInfo.type, // will always be CONDITIONAL here + halBarringInfo.serviceType, new BarringServiceInfo( + halBarringInfo.barringType, // will always be CONDITIONAL here conditionalInfo.isBarred, - conditionalInfo.barringFactor, - conditionalInfo.barringTimeSeconds)); + conditionalInfo.factor, + conditionalInfo.timeSeconds)); } else { // Barring type is either NONE or UNCONDITIONAL serviceInfos.put( - halBarringInfo.service, new BarringServiceInfo(halBarringInfo.type, - false, 0, 0)); + halBarringInfo.serviceType, new BarringServiceInfo( + halBarringInfo.barringType, false, 0, 0)); } } return new BarringInfo(ci, serviceInfos); @@ -321,6 +324,9 @@ public final class BarringInfo implements Parcelable { /** @hide */ @SystemApi public @NonNull BarringInfo createLocationInfoSanitizedCopy() { + // The only thing that would need sanitizing is the CellIdentity + if (mCellIdentity == null) return this; + return new BarringInfo(mCellIdentity.sanitizeLocationInfo(), mBarringServiceInfos); } diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 54c22ae282fb..708adebb6db3 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -265,10 +265,10 @@ public final class PreciseDataConnectionState implements Parcelable { /** * Return the APN Settings for this data connection. * - * Returns the ApnSetting that was used to configure this data connection. + * @return the ApnSetting that was used to configure this data connection. */ // FIXME: This shouldn't be nullable; update once the ApnSetting is supplied correctly - @Nullable ApnSetting getApnSetting() { + public @Nullable ApnSetting getApnSetting() { return mApnSetting; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 7406c8d5a33c..97f50fd314b8 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -55,7 +55,6 @@ import android.os.RemoteException; import android.provider.Telephony.SimInfo; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; -import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; @@ -2500,23 +2499,24 @@ public class SubscriptionManager { final SubscriptionInfo subInfo = SubscriptionManager.from(context).getActiveSubscriptionInfo(subId); - Configuration config = context.getResources().getConfiguration(); - Configuration newConfig = new Configuration(); - newConfig.setTo(config); + Configuration overrideConfig = new Configuration(); if (subInfo != null) { - newConfig.mcc = subInfo.getMcc(); - newConfig.mnc = subInfo.getMnc(); - if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO; + overrideConfig.mcc = subInfo.getMcc(); + overrideConfig.mnc = subInfo.getMnc(); + if (overrideConfig.mnc == 0) overrideConfig.mnc = Configuration.MNC_ZERO; } if (useRootLocale) { - newConfig.setLocale(Locale.ROOT); + overrideConfig.setLocale(Locale.ROOT); } - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - DisplayMetrics newMetrics = new DisplayMetrics(); - newMetrics.setTo(metrics); - Resources res = new Resources(context.getResources().getAssets(), newMetrics, newConfig); + // Create new context with new configuration so that we can avoid modifying the passed in + // context. + // Note that if the original context configuration changes, the resources here will also + // change for all values except those overridden by newConfig (e.g. if the device has an + // orientation change). + Context newContext = context.createConfigurationContext(overrideConfig); + Resources res = newContext.getResources(); if (cacheKey != null) { // Save the newly created Resources in the resource cache. diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java index 7ab4b56fae80..2d5df4f47e00 100644 --- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java @@ -27,12 +27,18 @@ 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 static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.content.Context; import android.os.PersistableBundle; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,15 +58,27 @@ public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); + @Mock private Context mContext; + @Mock private IConnectivityManager mService; @Mock private ConnectivityDiagnosticsCallback mCb; private ConnectivityDiagnosticsBinder mBinder; + private ConnectivityDiagnosticsManager mManager; @Before public void setUp() { + mContext = mock(Context.class); + mService = mock(IConnectivityManager.class); mCb = mock(ConnectivityDiagnosticsCallback.class); mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR); + mManager = new ConnectivityDiagnosticsManager(mContext, mService); + } + + @After + public void tearDown() { + // clear ConnectivityDiagnosticsManager callbacks map + ConnectivityDiagnosticsManager.sCallbacks.clear(); } private ConnectivityReport createSampleConnectivityReport() { @@ -245,4 +263,53 @@ public class ConnectivityDiagnosticsManagerTest { // latch without waiting. verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity)); } + + @Test + public void testRegisterConnectivityDiagnosticsCallback() throws Exception { + final NetworkRequest request = new NetworkRequest.Builder().build(); + + mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); + + verify(mService).registerConnectivityDiagnosticsCallback( + any(ConnectivityDiagnosticsBinder.class), eq(request)); + assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); + } + + @Test + public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception { + final NetworkRequest request = new NetworkRequest.Builder().build(); + + mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); + + try { + mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); + fail("Duplicate callback registration should fail"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testUnregisterConnectivityDiagnosticsCallback() throws Exception { + final NetworkRequest request = new NetworkRequest.Builder().build(); + mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); + + mManager.unregisterConnectivityDiagnosticsCallback(mCb); + + verify(mService).unregisterConnectivityDiagnosticsCallback( + any(ConnectivityDiagnosticsBinder.class)); + assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); + + // verify that re-registering is successful + mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb); + verify(mService, times(2)).registerConnectivityDiagnosticsCallback( + any(ConnectivityDiagnosticsBinder.class), eq(request)); + assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb)); + } + + @Test + public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception { + mManager.unregisterConnectivityDiagnosticsCallback(mCb); + + verifyNoMoreInteractions(mService); + } } diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java index 655c4d118592..97551c94e2ae 100644 --- a/tests/net/java/android/net/VpnManagerTest.java +++ b/tests/net/java/android/net/VpnManagerTest.java @@ -16,13 +16,21 @@ package android.net; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.test.mock.MockContext; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.net.VpnProfile; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,7 +39,12 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class VpnManagerTest { - private static final String VPN_PROFILE_KEY = "KEY"; + private static final String PKG_NAME = "fooPackage"; + + private static final String SESSION_NAME_STRING = "testSession"; + private static final String SERVER_ADDR_STRING = "1.2.3.4"; + private static final String IDENTITY_STRING = "Identity"; + private static final byte[] PSK_BYTES = "preSharedKey".getBytes(); private IConnectivityManager mMockCs; private VpnManager mVpnManager; @@ -39,7 +52,7 @@ public class VpnManagerTest { new MockContext() { @Override public String getOpPackageName() { - return "fooPackage"; + return PKG_NAME; } }; @@ -50,34 +63,49 @@ public class VpnManagerTest { } @Test - public void testProvisionVpnProfile() throws Exception { - try { - mVpnManager.provisionVpnProfile(mock(PlatformVpnProfile.class)); - } catch (UnsupportedOperationException expected) { - } + public void testProvisionVpnProfilePreconsented() throws Exception { + final PlatformVpnProfile profile = getPlatformVpnProfile(); + when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(true); + + // Expect there to be no intent returned, as consent has already been granted. + assertNull(mVpnManager.provisionVpnProfile(profile)); + verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME)); + } + + @Test + public void testProvisionVpnProfileNeedsConsent() throws Exception { + final PlatformVpnProfile profile = getPlatformVpnProfile(); + when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false); + + // Expect intent to be returned, as consent has not already been granted. + assertNotNull(mVpnManager.provisionVpnProfile(profile)); + verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME)); } @Test public void testDeleteProvisionedVpnProfile() throws Exception { - try { - mVpnManager.deleteProvisionedVpnProfile(); - } catch (UnsupportedOperationException expected) { - } + mVpnManager.deleteProvisionedVpnProfile(); + verify(mMockCs).deleteVpnProfile(eq(PKG_NAME)); } @Test public void testStartProvisionedVpnProfile() throws Exception { - try { - mVpnManager.startProvisionedVpnProfile(); - } catch (UnsupportedOperationException expected) { - } + mVpnManager.startProvisionedVpnProfile(); + verify(mMockCs).startVpnProfile(eq(PKG_NAME)); } @Test public void testStopProvisionedVpnProfile() throws Exception { - try { - mVpnManager.stopProvisionedVpnProfile(); - } catch (UnsupportedOperationException expected) { - } + mVpnManager.stopProvisionedVpnProfile(); + verify(mMockCs).stopVpnProfile(eq(PKG_NAME)); + } + + private Ikev2VpnProfile getPlatformVpnProfile() throws Exception { + return new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING) + .setBypassable(true) + .setMaxMtu(1300) + .setMetered(true) + .setAuthPsk(PSK_BYTES) + .build(); } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a0a1352a6330..5592cd7c2f9f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -139,6 +139,7 @@ import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; import android.net.ConnectivityThread; +import android.net.IConnectivityDiagnosticsCallback; import android.net.IDnsResolver; import android.net.IIpConnectivityMetrics; import android.net.INetd; @@ -180,6 +181,7 @@ import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Parcel; @@ -210,6 +212,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.connectivity.ConnectivityConstants; import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.IpConnectivityMetrics; @@ -322,6 +325,8 @@ public class ConnectivityServiceTest { @Mock UserManager mUserManager; @Mock NotificationManager mNotificationManager; @Mock AlarmManager mAlarmManager; + @Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback; + @Mock IBinder mIBinder; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -6355,4 +6360,70 @@ public class ConnectivityServiceTest { UserHandle.getAppId(uid)); return packageInfo; } + + @Test + public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception { + final NetworkRequest request = + new NetworkRequest( + new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE); + try { + mService.registerConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback, request); + fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception { + final NetworkRequest wifiRequest = + new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(); + + when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder); + + mService.registerConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback, wifiRequest); + + verify(mIBinder, timeout(TIMEOUT_MS)) + .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt()); + assertTrue( + mService.mConnectivityDiagnosticsCallbacks.containsKey( + mConnectivityDiagnosticsCallback)); + + mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback); + verify(mIBinder, timeout(TIMEOUT_MS)) + .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt()); + assertFalse( + mService.mConnectivityDiagnosticsCallbacks.containsKey( + mConnectivityDiagnosticsCallback)); + verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder(); + } + + @Test + public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception { + final NetworkRequest wifiRequest = + new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(); + when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder); + + mService.registerConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback, wifiRequest); + + verify(mIBinder, timeout(TIMEOUT_MS)) + .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt()); + verify(mConnectivityDiagnosticsCallback).asBinder(); + assertTrue( + mService.mConnectivityDiagnosticsCallbacks.containsKey( + mConnectivityDiagnosticsCallback)); + + // Register the same callback again + mService.registerConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback, wifiRequest); + + // Block until all other events are done processing. + HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + + assertTrue( + mService.mConnectivityDiagnosticsCallbacks.containsKey( + mConnectivityDiagnosticsCallback)); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index ce50bef53d75..084ec7330236 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -28,11 +28,11 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.net.RouteInfo.RTN_UNREACHABLE; 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 static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -43,6 +43,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -58,21 +59,20 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.IpPrefix; -import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; -import android.net.RouteInfo; import android.net.UidRange; import android.net.VpnService; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.INetworkManagementService; import android.os.Looper; -import android.os.SystemClock; +import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import android.security.Credentials; +import android.security.KeyStore; import android.util.ArrayMap; import android.util.ArraySet; @@ -81,6 +81,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnProfile; import org.junit.Before; import org.junit.Test; @@ -90,9 +91,6 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -124,6 +122,8 @@ public class VpnTest { managedProfileA.profileGroupId = primaryUser.id; } + static final String TEST_VPN_PKG = "com.dummy.vpn"; + /** * Names and UIDs for some fake packages. Important points: * - UID is ordered increasing. @@ -148,6 +148,8 @@ public class VpnTest { @Mock private NotificationManager mNotificationManager; @Mock private Vpn.SystemServices mSystemServices; @Mock private ConnectivityManager mConnectivityManager; + @Mock private KeyStore mKeyStore; + private final VpnProfile mVpnProfile = new VpnProfile("key"); @Before public void setUp() throws Exception { @@ -166,6 +168,7 @@ public class VpnTest { when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)) .thenReturn(Resources.getSystem().getString( R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)); + when(mSystemServices.isCallerSystem()).thenReturn(true); // Used by {@link Notification.Builder} ApplicationInfo applicationInfo = new ApplicationInfo(); @@ -175,6 +178,10 @@ public class VpnTest { .thenReturn(applicationInfo); doNothing().when(mNetService).registerObserver(any()); + + // Deny all appops by default. + when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString())) + .thenReturn(AppOpsManager.MODE_IGNORED); } @Test @@ -464,12 +471,12 @@ public class VpnTest { order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); // When a new VPN package is set the rules should change to cover that package. - vpn.prepare(null, PKGS[0]); + vpn.prepare(null, PKGS[0], false /* isPlatformVpn */); order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser)); order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0)); // When that VPN package is unset, everything should be undone again in reverse. - vpn.prepare(null, VpnConfig.LEGACY_VPN); + vpn.prepare(null, VpnConfig.LEGACY_VPN, false /* isPlatformVpn */); order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0)); order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser)); } @@ -632,6 +639,185 @@ public class VpnTest { } /** + * The profile name should NOT change between releases for backwards compatibility + * + * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST + * be updated to ensure backward compatibility. + */ + @Test + public void testGetProfileNameForPackage() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + setMockedUsers(primaryUser); + + final String expected = Credentials.PLATFORM_VPN + primaryUser.id + "_" + TEST_VPN_PKG; + assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG)); + } + + private Vpn createVpnAndSetupUidChecks(int... grantedOps) throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + setMockedUsers(primaryUser); + + when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt())) + .thenReturn(Process.myUid()); + + for (final int op : grantedOps) { + when(mAppOps.noteOpNoThrow(op, Process.myUid(), TEST_VPN_PKG)) + .thenReturn(AppOpsManager.MODE_ALLOWED); + } + + return vpn; + } + + private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, int... checkedOps) { + assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore)); + + // The profile should always be stored, whether or not consent has been previously granted. + verify(mKeyStore) + .put( + eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), + eq(mVpnProfile.encode()), + eq(Process.SYSTEM_UID), + eq(0)); + + for (final int checkedOp : checkedOps) { + verify(mAppOps).noteOpNoThrow(checkedOp, Process.myUid(), TEST_VPN_PKG); + } + } + + @Test + public void testProvisionVpnProfilePreconsented() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + + checkProvisionVpnProfile( + vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + } + + @Test + public void testProvisionVpnProfileNotPreconsented() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(); + + // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller + // had neither. + checkProvisionVpnProfile(vpn, false /* expectedResult */, + AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, AppOpsManager.OP_ACTIVATE_VPN); + } + + @Test + public void testProvisionVpnProfileVpnServicePreconsented() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN); + + checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_VPN); + } + + @Test + public void testProvisionVpnProfileTooLarge() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + + final VpnProfile bigProfile = new VpnProfile(""); + bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]); + + try { + vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile, mKeyStore); + fail("Expected IAE due to profile size"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testDeleteVpnProfile() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(); + + vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore); + + verify(mKeyStore) + .delete(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), eq(Process.SYSTEM_UID)); + } + + @Test + public void testGetVpnProfilePrivileged() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(); + + when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(new VpnProfile("").encode()); + + vpn.getVpnProfilePrivileged(TEST_VPN_PKG, mKeyStore); + + verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + } + + @Test + public void testStartVpnProfile() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + + when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + + vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + + verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + verify(mAppOps) + .noteOpNoThrow( + eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), + eq(Process.myUid()), + eq(TEST_VPN_PKG)); + } + + @Test + public void testStartVpnProfileVpnServicePreconsented() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN); + + when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + + vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + + // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown. + verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG); + } + + @Test + public void testStartVpnProfileNotConsented() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(); + + try { + vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + fail("Expected failure due to no user consent"); + } catch (SecurityException expected) { + } + + // Verify both appops were checked. + verify(mAppOps) + .noteOpNoThrow( + eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), + eq(Process.myUid()), + eq(TEST_VPN_PKG)); + verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG); + + // Keystore should never have been accessed. + verify(mKeyStore, never()).get(any()); + } + + @Test + public void testStartVpnProfileMissingProfile() throws Exception { + final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN); + + when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null); + + try { + vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + fail("Expected failure due to missing profile"); + } catch (IllegalArgumentException expected) { + } + + verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG)); + verify(mAppOps) + .noteOpNoThrow( + eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), + eq(Process.myUid()), + eq(TEST_VPN_PKG)); + } + + /** * Mock some methods of vpn object. */ private Vpn createVpn(@UserIdInt int userId) { diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index d290acae1967..8bccd7150050 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -40,18 +40,21 @@ AtomDecl::AtomDecl() { } -AtomDecl::AtomDecl(const AtomDecl& that) - : code(that.code), - name(that.name), - message(that.message), - fields(that.fields), - primaryFields(that.primaryFields), - exclusiveField(that.exclusiveField), - uidField(that.uidField), - whitelisted(that.whitelisted), - binaryFields(that.binaryFields), - hasModule(that.hasModule), - moduleName(that.moduleName) {} +AtomDecl::AtomDecl(const AtomDecl &that) + : code(that.code), + name(that.name), + message(that.message), + fields(that.fields), + primaryFields(that.primaryFields), + exclusiveField(that.exclusiveField), + defaultState(that.defaultState), + resetState(that.resetState), + nested(that.nested), + uidField(that.uidField), + whitelisted(that.whitelisted), + binaryFields(that.binaryFields), + hasModule(that.hasModule), + moduleName(that.moduleName) {} AtomDecl::AtomDecl(int c, const string& n, const string& m) :code(c), @@ -281,7 +284,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, atomDecl->fields.push_back(atField); if (field->options().GetExtension(os::statsd::state_field_option).option() == - os::statsd::StateField::PRIMARY) { + os::statsd::StateField::PRIMARY_FIELD) { if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { @@ -300,7 +303,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, } if (field->options().GetExtension(os::statsd::state_field_option).option() == - os::statsd::StateField::EXCLUSIVE) { + os::statsd::StateField::EXCLUSIVE_STATE) { if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { @@ -312,6 +315,21 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, } else { errorCount++; } + + if (field->options() + .GetExtension(os::statsd::state_field_option) + .has_default_state_value()) { + atomDecl->defaultState = field->options() + .GetExtension(os::statsd::state_field_option) + .default_state_value(); + } + + if (field->options().GetExtension(os::statsd::state_field_option).has_reset_state_value()) { + atomDecl->resetState = field->options() + .GetExtension(os::statsd::state_field_option) + .reset_state_value(); + } + atomDecl->nested = field->options().GetExtension(os::statsd::state_field_option).nested(); } if (field->options().GetExtension(os::statsd::is_uid) == true) { diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 87d4d5db0cee..65d8e3efee5b 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -88,6 +88,9 @@ struct AtomDecl { vector<int> primaryFields; int exclusiveField = 0; + int defaultState = INT_MAX; + int resetState = INT_MAX; + bool nested; int uidField = 0; diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp index 66ae96401974..984c929f63bd 100644 --- a/tools/stats_log_api_gen/atoms_info_writer.cpp +++ b/tools/stats_log_api_gen/atoms_info_writer.cpp @@ -25,11 +25,15 @@ namespace android { namespace stats_log_api_gen { static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) { + fprintf(out, "static int UNSET_VALUE = INT_MAX;\n"); fprintf(out, "static int FIRST_UID_IN_CHAIN = 0;\n"); fprintf(out, "struct StateAtomFieldOptions {\n"); fprintf(out, " std::vector<int> primaryFields;\n"); fprintf(out, " int exclusiveField;\n"); + fprintf(out, " int defaultState = UNSET_VALUE;\n"); + fprintf(out, " int resetState = UNSET_VALUE;\n"); + fprintf(out, " bool nested;\n"); fprintf(out, "};\n"); fprintf(out, "\n"); @@ -126,7 +130,7 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) { "static std::map<int, StateAtomFieldOptions> " "getStateAtomFieldOptions() {\n"); fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); - fprintf(out, " StateAtomFieldOptions opt;\n"); + fprintf(out, " StateAtomFieldOptions* opt;\n"); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end(); atom++) { if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { @@ -136,14 +140,26 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) { "\n // Adding primary and exclusive fields for atom " "(%d)%s\n", atom->code, atom->name.c_str()); - fprintf(out, " opt.primaryFields.clear();\n"); + fprintf(out, " opt = &(options[static_cast<int>(%s)]);\n", + make_constant_name(atom->name).c_str()); + fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size()); for (const auto& field : atom->primaryFields) { - fprintf(out, " opt.primaryFields.push_back(%d);\n", field); + fprintf(out, " opt->primaryFields.push_back(%d);\n", field); } - fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); - fprintf(out, " options[static_cast<int>(%s)] = opt;\n", - make_constant_name(atom->name).c_str()); + fprintf(out, " opt->exclusiveField = %d;\n", atom->exclusiveField); + if (atom->defaultState != INT_MAX) { + fprintf(out, " opt->defaultState = %d;\n", atom->defaultState); + } else { + fprintf(out, " opt->defaultState = UNSET_VALUE;\n"); + } + + if (atom->resetState != INT_MAX) { + fprintf(out, " opt->resetState = %d;\n", atom->resetState); + } else { + fprintf(out, " opt->resetState = UNSET_VALUE;\n"); + } + fprintf(out, " opt->nested = %d;\n", atom->nested); } fprintf(out, " return options;\n"); diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto index c9a47632b4bb..b892194410ae 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -148,53 +148,42 @@ message GoodStateAtoms { // The atom has only primary field but no exclusive state field. message BadStateAtom1 { - optional int32 uid = 1 - [(android.os.statsd.state_field_option).option = PRIMARY]; + optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; } // Only primative types can be annotated. message BadStateAtom2 { repeated android.os.statsd.AttributionNode attribution = 1 - [(android.os.statsd.state_field_option).option = PRIMARY]; - optional int32 state = 2 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; + [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; + optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; } // Having 2 exclusive state field in the atom means the atom is badly designed. // E.g., putting bluetooth state and wifi state in the same atom. message BadStateAtom3 { - optional int32 uid = 1 - [(android.os.statsd.state_field_option).option = PRIMARY]; - optional int32 state = 2 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; - optional int32 state2 = 3 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; + optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; + optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; + optional int32 state2 = 3 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; } message GoodStateAtom1 { - optional int32 uid = 1 - [(android.os.statsd.state_field_option).option = PRIMARY]; - optional int32 state = 2 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; + optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; + optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; } // Atoms can have exclusive state field, but no primary field. That means // the state is globally exclusive (e.g., DisplayState). message GoodStateAtom2 { optional int32 uid = 1; - optional int32 state = 2 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; + optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; } // We can have more than one primary fields. That means their combination is a // primary key. message GoodStateAtom3 { - optional int32 uid = 1 - [(android.os.statsd.state_field_option).option = PRIMARY]; - optional int32 tid = 2 - [(android.os.statsd.state_field_option).option = PRIMARY]; - optional int32 state = 3 - [(android.os.statsd.state_field_option).option = EXCLUSIVE]; + optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; + optional int32 tid = 2 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD]; + optional int32 state = 3 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE]; } message WhitelistedAtom { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 8d95cb010856..91b7df372e01 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -1252,8 +1252,8 @@ public class WifiConfiguration implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - NETWORK_SELECTION_ENABLE, + @IntDef(prefix = "DISABLED_", value = { + DISABLED_NONE, DISABLED_ASSOCIATION_REJECTION, DISABLED_AUTHENTICATION_FAILURE, DISABLED_DHCP_FAILURE, @@ -1267,7 +1267,7 @@ public class WifiConfiguration implements Parcelable { // Quality Network disabled reasons /** Default value. Means not disabled. */ - public static final int NETWORK_SELECTION_ENABLE = 0; + public static final int DISABLED_NONE = 0; /** * The starting index for network selection disabled reasons. * @hide @@ -1356,7 +1356,7 @@ public class WifiConfiguration implements Parcelable { private static SparseArray<DisableReasonInfo> buildDisableReasonInfos() { SparseArray<DisableReasonInfo> reasons = new SparseArray<>(); - reasons.append(NETWORK_SELECTION_ENABLE, + reasons.append(DISABLED_NONE, new DisableReasonInfo( // Note that these strings are persisted in // XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml, @@ -1610,7 +1610,7 @@ public class WifiConfiguration implements Parcelable { } /** True if the device has ever connected to this network, false otherwise. */ - public boolean getHasEverConnected() { + public boolean hasEverConnected() { return mHasEverConnected; } @@ -1650,7 +1650,7 @@ public class WifiConfiguration implements Parcelable { /** * * Set the current network's disable reason. - * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants. + * One of the {@link #DISABLED_NONE} or DISABLED_* constants. * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. * @see NetworkSelectionStatus#getNetworkSelectionDisableReason() */ @@ -1674,7 +1674,7 @@ public class WifiConfiguration implements Parcelable { /** * Get the network disable reason string for a reason code (for debugging). - * @param reason specific error reason. One of the {@link #NETWORK_SELECTION_ENABLE} or + * @param reason specific error reason. One of the {@link #DISABLED_NONE} or * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. * @return network disable reason string, or null if the reason is invalid. */ @@ -1740,7 +1740,7 @@ public class WifiConfiguration implements Parcelable { /** * Returns the current network's disable reason. - * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants + * One of the {@link #DISABLED_NONE} or DISABLED_* constants * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. */ @NetworkSelectionDisableReason @@ -1780,13 +1780,13 @@ public class WifiConfiguration implements Parcelable { /** * Get the disable counter of a specific reason. - * @param reason specific failure reason. One of the {@link #NETWORK_SELECTION_ENABLE} or + * @param reason specific failure reason. One of the {@link #DISABLED_NONE} or * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. * @exception IllegalArgumentException for invalid reason * @return counter number for specific error reason. */ public int getDisableReasonCounter(@NetworkSelectionDisableReason int reason) { - if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { + if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) { return mNetworkSeclectionDisableCounter[reason]; } else { throw new IllegalArgumentException("Illegal reason value: " + reason); @@ -1801,7 +1801,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ public void setDisableReasonCounter(int reason, int value) { - if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { + if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) { mNetworkSeclectionDisableCounter[reason] = value; } else { throw new IllegalArgumentException("Illegal reason value: " + reason); @@ -1815,7 +1815,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ public void incrementDisableReasonCounter(int reason) { - if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { + if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) { mNetworkSeclectionDisableCounter[reason]++; } else { throw new IllegalArgumentException("Illegal reason value: " + reason); @@ -1829,8 +1829,8 @@ public class WifiConfiguration implements Parcelable { * @hide */ public void clearDisableReasonCounter(int reason) { - if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { - mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE; + if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) { + mNetworkSeclectionDisableCounter[reason] = DISABLED_NONE; } else { throw new IllegalArgumentException("Illegal reason value: " + reason); } @@ -1841,7 +1841,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ public void clearDisableReasonCounter() { - Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE); + Arrays.fill(mNetworkSeclectionDisableCounter, DISABLED_NONE); } /** @@ -1871,7 +1871,7 @@ public class WifiConfiguration implements Parcelable { public void copy(NetworkSelectionStatus source) { mStatus = source.mStatus; mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason; - for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX; + for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX; index++) { mNetworkSeclectionDisableCounter[index] = source.mNetworkSeclectionDisableCounter[index]; @@ -1882,14 +1882,14 @@ public class WifiConfiguration implements Parcelable { setCandidate(source.getCandidate()); setCandidateScore(source.getCandidateScore()); setConnectChoice(source.getConnectChoice()); - setHasEverConnected(source.getHasEverConnected()); + setHasEverConnected(source.hasEverConnected()); } /** @hide */ public void writeToParcel(Parcel dest) { dest.writeInt(getNetworkSelectionStatus()); dest.writeInt(getNetworkSelectionDisableReason()); - for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX; + for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX; index++) { dest.writeInt(getDisableReasonCounter(index)); } @@ -1901,14 +1901,14 @@ public class WifiConfiguration implements Parcelable { } else { dest.writeInt(CONNECT_CHOICE_NOT_EXISTS); } - dest.writeInt(getHasEverConnected() ? 1 : 0); + dest.writeInt(hasEverConnected() ? 1 : 0); } /** @hide */ public void readFromParcel(Parcel in) { setNetworkSelectionStatus(in.readInt()); setNetworkSelectionDisableReason(in.readInt()); - for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX; + for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX; index++) { setDisableReasonCounter(index, in.readInt()); } @@ -2151,8 +2151,8 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" mNetworkSelectionDisableReason ") .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n"); - for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE; - index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) { + for (int index = NetworkSelectionStatus.DISABLED_NONE; + index < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) { if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) { sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index) + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index) @@ -2164,7 +2164,7 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice()); } sbuf.append(" hasEverConnected: ") - .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n"); + .append(mNetworkSelectionStatus.hasEverConnected()).append("\n"); if (this.numAssociation > 0) { sbuf.append(" numAssociation ").append(this.numAssociation).append("\n"); @@ -2533,7 +2533,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ @Nullable - @SystemApi + @UnsupportedAppUsage public StaticIpConfiguration getStaticIpConfiguration() { return mIpConfiguration.getStaticIpConfiguration(); } @@ -2549,7 +2549,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ @NonNull - @SystemApi + @UnsupportedAppUsage public IpConfiguration.IpAssignment getIpAssignment() { return mIpConfiguration.getIpAssignment(); } @@ -2565,7 +2565,7 @@ public class WifiConfiguration implements Parcelable { * @hide */ @NonNull - @SystemApi + @UnsupportedAppUsage public IpConfiguration.ProxySettings getProxySettings() { return mIpConfiguration.getProxySettings(); } @@ -2628,7 +2628,7 @@ public class WifiConfiguration implements Parcelable { * Set the {@link ProxySettings} and {@link ProxyInfo} for this network. * @hide */ - @SystemApi + @UnsupportedAppUsage public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) { mIpConfiguration.setProxySettings(settings); mIpConfiguration.setHttpProxy(proxy); diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 04016b606b96..db0d36e5c086 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -60,13 +60,13 @@ public class WifiEnterpriseConfig implements Parcelable { "android.net.wifi.extra.WAPI_AS_CERTIFICATE_DATA"; /** - * Intent extra: name for WAPI AS certificates + * Intent extra: name for WAPI USER certificates */ public static final String EXTRA_WAPI_USER_CERTIFICATE_NAME = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_NAME"; /** - * Intent extra: data for WAPI AS certificates + * Intent extra: data for WAPI USER certificates */ public static final String EXTRA_WAPI_USER_CERTIFICATE_DATA = "android.net.wifi.extra.WAPI_USER_CERTIFICATE_DATA"; |