diff options
265 files changed, 6457 insertions, 1379 deletions
diff --git a/api/current.txt b/api/current.txt index 812134f1a280..bef160cc977e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6420,6 +6420,7 @@ package android.app.admin { method public android.content.ComponentName getMandatoryBackupTransport(); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); + method public java.util.List<java.lang.String> getMeteredDataDisabled(android.content.ComponentName); method public int getOrganizationColor(android.content.ComponentName); method public java.lang.CharSequence getOrganizationName(android.content.ComponentName); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); @@ -6524,6 +6525,7 @@ package android.app.admin { method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); + method public java.util.List<java.lang.String> setMeteredDataDisabled(android.content.ComponentName, java.util.List<java.lang.String>); method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean); method public void setOrganizationColor(android.content.ComponentName, int); method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence); @@ -7100,6 +7102,7 @@ package android.app.slice { field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR; field public static final java.lang.String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE"; field public static final java.lang.String HINT_ACTIONS = "actions"; + field public static final java.lang.String HINT_CALLER_NEEDED = "caller_needed"; field public static final java.lang.String HINT_HORIZONTAL = "horizontal"; field public static final java.lang.String HINT_LARGE = "large"; field public static final java.lang.String HINT_LIST = "list"; @@ -7128,8 +7131,6 @@ package android.app.slice { method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice, java.lang.String); method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.lang.String...); method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.util.List<java.lang.String>); - method public deprecated android.app.slice.Slice.Builder addColor(int, java.lang.String, java.lang.String...); - method public deprecated android.app.slice.Slice.Builder addColor(int, java.lang.String, java.util.List<java.lang.String>); method public android.app.slice.Slice.Builder addHints(java.lang.String...); method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>); method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.lang.String...); @@ -7152,7 +7153,6 @@ package android.app.slice { method public int describeContents(); method public android.app.PendingIntent getAction(); method public android.os.Bundle getBundle(); - method public deprecated int getColor(); method public java.lang.String getFormat(); method public java.util.List<java.lang.String> getHints(); method public android.graphics.drawable.Icon getIcon(); @@ -7167,7 +7167,6 @@ package android.app.slice { field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR; field public static final java.lang.String FORMAT_ACTION = "action"; field public static final java.lang.String FORMAT_BUNDLE = "bundle"; - field public static final deprecated java.lang.String FORMAT_COLOR = "color"; field public static final java.lang.String FORMAT_IMAGE = "image"; field public static final java.lang.String FORMAT_INT = "int"; field public static final java.lang.String FORMAT_REMOTE_INPUT = "input"; @@ -7197,6 +7196,7 @@ package android.app.slice { public abstract class SliceProvider extends android.content.ContentProvider { ctor public SliceProvider(); method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); + method public final java.lang.String getBindingPackage(); method public final java.lang.String getType(android.net.Uri); method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues); method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>); @@ -11533,15 +11533,15 @@ package android.content.res { public final class AssetManager implements java.lang.AutoCloseable { method public void close(); - method public final java.lang.String[] getLocales(); - method public final java.lang.String[] list(java.lang.String) throws java.io.IOException; - method public final java.io.InputStream open(java.lang.String) throws java.io.IOException; - method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException; - method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException; - method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException; - method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException; + method public java.lang.String[] getLocales(); + method public java.lang.String[] list(java.lang.String) throws java.io.IOException; + method public java.io.InputStream open(java.lang.String) throws java.io.IOException; + method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException; + method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException; + method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException; + method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException; field public static final int ACCESS_BUFFER = 3; // 0x3 field public static final int ACCESS_RANDOM = 1; // 0x1 field public static final int ACCESS_STREAMING = 2; // 0x2 @@ -23137,24 +23137,29 @@ package android.media { method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence); } - public final class MediaDrm { + public final class MediaDrm implements java.lang.AutoCloseable { ctor public MediaDrm(java.util.UUID) throws android.media.UnsupportedSchemeException; + method public void close(); method public void closeSession(byte[]); - method protected void finalize(); + method public int getConnectedHdcpLevel(); method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String); method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException; + method public int getMaxHdcpLevel(); + method public int getMaxSessionCount(); + method public int getOpenSessionCount(); method public byte[] getPropertyByteArray(java.lang.String); method public java.lang.String getPropertyString(java.lang.String); method public android.media.MediaDrm.ProvisionRequest getProvisionRequest(); method public byte[] getSecureStop(byte[]); method public java.util.List<byte[]> getSecureStops(); + method public int getSecurityLevel(byte[]); method public static final boolean isCryptoSchemeSupported(java.util.UUID); method public static final boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String); method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException; method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException; method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]); - method public final void release(); + method public deprecated void release(); method public void releaseAllSecureStops(); method public void releaseSecureStops(byte[]); method public void removeKeys(byte[]); @@ -23164,11 +23169,22 @@ package android.media { method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler); method public void setPropertyByteArray(java.lang.String, byte[]); method public void setPropertyString(java.lang.String, java.lang.String); + method public void setSecurityLevel(byte[], int); field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3 field public static final int EVENT_KEY_REQUIRED = 2; // 0x2 field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1 field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5 field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4 + field public static final int HDCP_LEVEL_UNKNOWN = 0; // 0x0 + field public static final int HDCP_NONE = 1; // 0x1 + field public static final int HDCP_NO_DIGITAL_OUTPUT = 2147483647; // 0x7fffffff + field public static final int HDCP_V1 = 2; // 0x2 + field public static final int HDCP_V2 = 3; // 0x3 + field public static final int HDCP_V2_1 = 4; // 0x4 + field public static final int HDCP_V2_2 = 5; // 0x5 + field public static final int HW_SECURE_ALL = 5; // 0x5 + field public static final int HW_SECURE_CRYPTO = 3; // 0x3 + field public static final int HW_SECURE_DECODE = 4; // 0x4 field public static final int KEY_TYPE_OFFLINE = 2; // 0x2 field public static final int KEY_TYPE_RELEASE = 3; // 0x3 field public static final int KEY_TYPE_STREAMING = 1; // 0x1 @@ -23177,6 +23193,9 @@ package android.media { field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId"; field public static final java.lang.String PROPERTY_VENDOR = "vendor"; field public static final java.lang.String PROPERTY_VERSION = "version"; + field public static final int SECURITY_LEVEL_UNKNOWN = 0; // 0x0 + field public static final int SW_SECURE_CRYPTO = 1; // 0x1 + field public static final int SW_SECURE_DECODE = 2; // 0x2 } public final class MediaDrm.CryptoSession { @@ -23186,6 +23205,9 @@ package android.media { method public boolean verify(byte[], byte[], byte[]); } + public static abstract class MediaDrm.HdcpLevel implements java.lang.annotation.Annotation { + } + public static final class MediaDrm.KeyRequest { method public byte[] getData(); method public java.lang.String getDefaultUrl(); @@ -23226,6 +23248,9 @@ package android.media { method public java.lang.String getDefaultUrl(); } + public static abstract class MediaDrm.SecurityLevel implements java.lang.annotation.Annotation { + } + public class MediaDrmException extends java.lang.Exception { ctor public MediaDrmException(java.lang.String); } @@ -35838,7 +35863,6 @@ package android.provider { field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS"; field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS"; field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS"; - field public static final java.lang.String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS"; field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS"; field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS"; field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS"; @@ -35899,7 +35923,6 @@ package android.provider { field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE"; field public static final java.lang.String EXTRA_AUTHORITIES = "authorities"; field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled"; - field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID"; field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID"; field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled"; field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes"; @@ -37833,6 +37856,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isInvalidatedByBiometricEnrollment(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isStrongBoxBacked(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationValidWhileOnBody(); } @@ -37850,6 +37874,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setIsStrongBoxBacked(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); @@ -37910,6 +37935,7 @@ package android.security.keystore { field public static final java.lang.String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; + field public static final deprecated java.lang.String KEY_ALGORITHM_3DES = "DESede"; field public static final java.lang.String KEY_ALGORITHM_AES = "AES"; field public static final java.lang.String KEY_ALGORITHM_EC = "EC"; field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; @@ -37920,11 +37946,13 @@ package android.security.keystore { field public static final java.lang.String KEY_ALGORITHM_RSA = "RSA"; field public static final int ORIGIN_GENERATED = 1; // 0x1 field public static final int ORIGIN_IMPORTED = 2; // 0x2 + field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8 field public static final int ORIGIN_UNKNOWN = 4; // 0x4 field public static final int PURPOSE_DECRYPT = 2; // 0x2 field public static final int PURPOSE_ENCRYPT = 1; // 0x1 field public static final int PURPOSE_SIGN = 4; // 0x4 field public static final int PURPOSE_VERIFY = 8; // 0x8 + field public static final int PURPOSE_WRAP_KEY = 32; // 0x20 field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS"; } @@ -37964,12 +37992,24 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } + public class StrongBoxUnavailableException extends java.security.ProviderException { + ctor public StrongBoxUnavailableException(); + } + public class UserNotAuthenticatedException extends java.security.InvalidKeyException { ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable); } + public class WrappedKeyEntry implements java.security.KeyStore.Entry { + ctor public WrappedKeyEntry(byte[], java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec); + method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); + method public java.lang.String getTransformation(); + method public byte[] getWrappedKeyBytes(); + method public java.lang.String getWrappingKeyAlias(); + } + } package android.service.autofill { @@ -40861,6 +40901,7 @@ package android.telephony { field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string"; field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string"; field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string"; + field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; field public static final java.lang.String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool"; field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool"; field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long"; @@ -41554,10 +41595,16 @@ package android.telephony { method public static int getDefaultSmsSubscriptionId(); method public static int getDefaultSubscriptionId(); method public static int getDefaultVoiceSubscriptionId(); + method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); method public boolean isNetworkRoaming(int); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); + method public void setSubscriptionOverrideCongested(int, boolean, long); + method public void setSubscriptionOverrideUnmetered(int, boolean, long); + method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>); field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED"; field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; + field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; + field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; field public static final int DATA_ROAMING_DISABLE = 0; // 0x0 field public static final int DATA_ROAMING_ENABLE = 1; // 0x1 field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX"; @@ -41569,6 +41616,38 @@ package android.telephony { method public void onSubscriptionsChanged(); } + public final class SubscriptionPlan implements android.os.Parcelable { + method public java.util.Iterator<android.util.Pair<java.time.ZonedDateTime, java.time.ZonedDateTime>> cycleIterator(); + method public int describeContents(); + method public int getDataLimitBehavior(); + method public long getDataLimitBytes(); + method public long getDataUsageBytes(); + method public long getDataUsageTime(); + method public java.lang.CharSequence getSummary(); + method public java.lang.CharSequence getTitle(); + method public void writeToParcel(android.os.Parcel, int); + field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL + field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL + field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionPlan> CREATOR; + field public static final int LIMIT_BEHAVIOR_BILLED = 1; // 0x1 + field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0 + field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2 + field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff + field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL + } + + public static class SubscriptionPlan.Builder { + method public android.telephony.SubscriptionPlan build(); + method public static android.telephony.SubscriptionPlan.Builder createNonrecurring(java.time.ZonedDateTime, java.time.ZonedDateTime); + method public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime); + method public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime); + method public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime); + method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); + method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); + method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence); + method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence); + } + public class TelephonyManager { method public boolean canChangeDtmfToneLength(); method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); @@ -47832,6 +47911,7 @@ package android.view { method protected final int getLocalFeatures(); method public android.media.session.MediaController getMediaController(); method public abstract int getNavigationBarColor(); + method public int getNavigationBarDividerColor(); method public android.transition.Transition getReenterTransition(); method public android.transition.Transition getReturnTransition(); method public android.transition.Transition getSharedElementEnterTransition(); @@ -47900,6 +47980,7 @@ package android.view { method public void setLogo(int); method public void setMediaController(android.media.session.MediaController); method public abstract void setNavigationBarColor(int); + method public void setNavigationBarDividerColor(int); method public void setReenterTransition(android.transition.Transition); method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable); method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener); diff --git a/api/system-current.txt b/api/system-current.txt index 97f82e99fe6e..bfe44c9198a4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4605,18 +4605,21 @@ package android.telephony.data { method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int); field public static final java.lang.String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID"; field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService"; + field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3 + field public static final int REQUEST_REASON_NORMAL = 1; // 0x1 + field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2 } public class DataService.DataServiceProvider { ctor public DataService.DataServiceProvider(int); - method public void deactivateDataCall(int, boolean, boolean, android.telephony.data.DataServiceCallback); + method public void deactivateDataCall(int, int, android.telephony.data.DataServiceCallback); method public void getDataCallList(android.telephony.data.DataServiceCallback); method public final int getSlotId(); method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); method protected void onDestroy(); method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, android.telephony.data.DataServiceCallback); method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, android.telephony.data.DataServiceCallback); - method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, boolean, android.net.LinkProperties, android.telephony.data.DataServiceCallback); + method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, int, android.net.LinkProperties, android.telephony.data.DataServiceCallback); } public class DataServiceCallback { diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk index 368a70bc3898..2b00d9e6a596 100644 --- a/cmds/incidentd/Android.mk +++ b/cmds/incidentd/Android.mk @@ -91,9 +91,7 @@ GEN_PROTO:= gen_src_dir:= -ifeq ($(BUILD_WITH_INCIDENTD_RC), true) LOCAL_INIT_RC := incidentd.rc -endif include $(BUILD_EXECUTABLE) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 7a9588d1a2c4..7f0ebb45e2d7 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -86,6 +86,7 @@ message Atom { AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50; LmkEventOccurred lmk_event_occurred = 51; PictureInPictureStateChanged picture_in_picture_state_changed = 52; + WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53; // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } @@ -707,6 +708,22 @@ message WifiScanStateChanged { } /** + * Logs wifi multicast locks held by an app + * + * Logged from: + * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java + */ +message WifiMulticastLockStateChanged { + repeated AttributionNode attribution_node = 1; + + enum State { + OFF = 0; + ON = 1; + } + optional State state = 2; +} + +/** * Logs phone signal strength changes. * * Logged from: @@ -1322,4 +1339,4 @@ message SystemUptime { // for external input). // It is not affected by clock scaling, idle, or other power saving mechanisms. optional uint64 uptime_ms = 1; -}
\ No newline at end of file +} diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index bb2193fb442b..f73c4a5303cf 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -188,78 +188,78 @@ message ConfigMetricsReportList { } message StatsdStatsReport { - optional int32 stats_begin_time_sec = 1; + optional int32 stats_begin_time_sec = 1; - optional int32 stats_end_time_sec = 2; + optional int32 stats_end_time_sec = 2; - message MatcherStats { - optional int64 id = 1; - optional int32 matched_times = 2; - } + message MatcherStats { + optional int64 id = 1; + optional int32 matched_times = 2; + } - message ConditionStats { - optional int64 id = 1; - optional int32 max_tuple_counts = 2; - } + message ConditionStats { + optional int64 id = 1; + optional int32 max_tuple_counts = 2; + } - message MetricStats { - optional int64 id = 1; - optional int32 max_tuple_counts = 2; - } + message MetricStats { + optional int64 id = 1; + optional int32 max_tuple_counts = 2; + } - message AlertStats { - optional int64 id = 1; - optional int32 alerted_times = 2; - } + message AlertStats { + optional int64 id = 1; + optional int32 alerted_times = 2; + } - message ConfigStats { - optional int32 uid = 1; - optional int64 id = 2; - optional int32 creation_time_sec = 3; - optional int32 deletion_time_sec = 4; - optional int32 metric_count = 5; - optional int32 condition_count = 6; - optional int32 matcher_count = 7; - optional int32 alert_count = 8; - optional bool is_valid = 9; - - repeated int32 broadcast_sent_time_sec = 10; - repeated int32 data_drop_time_sec = 11; - repeated int32 dump_report_time_sec = 12; - repeated MatcherStats matcher_stats = 13; - repeated ConditionStats condition_stats = 14; - repeated MetricStats metric_stats = 15; - repeated AlertStats alert_stats = 16; - } + message ConfigStats { + optional int32 uid = 1; + optional int64 id = 2; + optional int32 creation_time_sec = 3; + optional int32 deletion_time_sec = 4; + optional int32 metric_count = 5; + optional int32 condition_count = 6; + optional int32 matcher_count = 7; + optional int32 alert_count = 8; + optional bool is_valid = 9; + + repeated int32 broadcast_sent_time_sec = 10; + repeated int32 data_drop_time_sec = 11; + repeated int32 dump_report_time_sec = 12; + repeated MatcherStats matcher_stats = 13; + repeated ConditionStats condition_stats = 14; + repeated MetricStats metric_stats = 15; + repeated AlertStats alert_stats = 16; + } - repeated ConfigStats config_stats = 3; + repeated ConfigStats config_stats = 3; - message AtomStats { - optional int32 tag = 1; - optional int32 count = 2; - } + message AtomStats { + optional int32 tag = 1; + optional int32 count = 2; + } - repeated AtomStats atom_stats = 7; + repeated AtomStats atom_stats = 7; - message UidMapStats { - optional int32 snapshots = 1; - optional int32 changes = 2; - optional int32 bytes_used = 3; - optional int32 dropped_snapshots = 4; - optional int32 dropped_changes = 5; - } - optional UidMapStats uidmap_stats = 8; + message UidMapStats { + optional int32 snapshots = 1; + optional int32 changes = 2; + optional int32 bytes_used = 3; + optional int32 dropped_snapshots = 4; + optional int32 dropped_changes = 5; + } + optional UidMapStats uidmap_stats = 8; - message AnomalyAlarmStats { - optional int32 alarms_registered = 1; - } - optional AnomalyAlarmStats anomaly_alarm_stats = 9; + message AnomalyAlarmStats { + optional int32 alarms_registered = 1; + } + optional AnomalyAlarmStats anomaly_alarm_stats = 9; - message PulledAtomStats { - optional int32 atom_id = 1; - optional int64 total_pull = 2; - optional int64 total_pull_from_cache = 3; - optional int64 min_pull_interval_sec = 4; - } - repeated PulledAtomStats pulled_atom_stats = 10; + message PulledAtomStats { + optional int32 atom_id = 1; + optional int64 total_pull = 2; + optional int64 total_pull_from_cache = 3; + optional int64 min_pull_interval_sec = 4; + } + repeated PulledAtomStats pulled_atom_stats = 10; }
\ No newline at end of file diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index cd60ee74e3ad..07bbcb2190e8 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -25,300 +25,303 @@ option java_outer_classname = "StatsdConfigProto"; import "frameworks/base/cmds/statsd/src/perfetto/perfetto_config.proto"; enum Position { - POSITION_UNKNOWN = 0; - FIRST = 1; - LAST = 2; - ANY = 3; + POSITION_UNKNOWN = 0; + + FIRST = 1; + + LAST = 2; + + ANY = 3; } enum TimeUnit { - TIME_UNIT_UNSPECIFIED = 0; - ONE_MINUTE = 1; - FIVE_MINUTES = 2; - TEN_MINUTES = 3; - THIRTY_MINUTES = 4; - ONE_HOUR = 5; - THREE_HOURS = 6; - SIX_HOURS = 7; - TWELVE_HOURS = 8; - ONE_DAY = 9; - CTS = 1000; + TIME_UNIT_UNSPECIFIED = 0; + ONE_MINUTE = 1; + FIVE_MINUTES = 2; + TEN_MINUTES = 3; + THIRTY_MINUTES = 4; + ONE_HOUR = 5; + THREE_HOURS = 6; + SIX_HOURS = 7; + TWELVE_HOURS = 8; + ONE_DAY = 9; + CTS = 1000; } message FieldMatcher { - optional int32 field = 1; + optional int32 field = 1; - optional Position position = 2; + optional Position position = 2; - repeated FieldMatcher child = 3; + repeated FieldMatcher child = 3; } message FieldValueMatcher { - // Field id, as specified in the atom proto message. - optional int32 field = 1; - - // For repeated fields, specifies the position in the array. - // FIRST and LAST mean that if the values are found at the first - // or last position, it's a match. ANY means that if the values are found - // anywhere in the array, then it's a match. - optional Position position = 2; - - oneof value_matcher { - bool eq_bool = 3; - string eq_string = 4; - int32 eq_int = 5; - - int64 lt_int = 6; - int64 gt_int = 7; - float lt_float = 8; - float gt_float = 9; - - int64 lte_int = 10; - int64 gte_int = 11; - - MessageMatcher matches_tuple = 12; - } + optional int32 field = 1; + + optional Position position = 2; + + oneof value_matcher { + bool eq_bool = 3; + string eq_string = 4; + int32 eq_int = 5; + + int64 lt_int = 6; + int64 gt_int = 7; + float lt_float = 8; + float gt_float = 9; + + int64 lte_int = 10; + int64 gte_int = 11; + + MessageMatcher matches_tuple = 12; + } } message MessageMatcher { - repeated FieldValueMatcher field_value_matcher = 1; + repeated FieldValueMatcher field_value_matcher = 1; } enum LogicalOperation { - LOGICAL_OPERATION_UNSPECIFIED = 0; - AND = 1; - OR = 2; - NOT = 3; - NAND = 4; - NOR = 5; + LOGICAL_OPERATION_UNSPECIFIED = 0; + AND = 1; + OR = 2; + NOT = 3; + NAND = 4; + NOR = 5; } message SimpleAtomMatcher { - optional int32 atom_id = 1; + optional int32 atom_id = 1; - repeated FieldValueMatcher field_value_matcher = 2; + repeated FieldValueMatcher field_value_matcher = 2; } message AtomMatcher { - optional int64 id = 1; + optional int64 id = 1; - message Combination { - optional LogicalOperation operation = 1; + message Combination { + optional LogicalOperation operation = 1; - repeated int64 matcher = 2; - } - oneof contents { - SimpleAtomMatcher simple_atom_matcher = 2; - Combination combination = 3; - } + repeated int64 matcher = 2; + } + oneof contents { + SimpleAtomMatcher simple_atom_matcher = 2; + Combination combination = 3; + } } message SimplePredicate { - optional int64 start = 1; + optional int64 start = 1; - optional int64 stop = 2; + optional int64 stop = 2; - optional bool count_nesting = 3 [default = true]; + optional bool count_nesting = 3 [default = true]; - optional int64 stop_all = 4; + optional int64 stop_all = 4; - enum InitialValue { - UNKNOWN = 0; - FALSE = 1; - } - optional InitialValue initial_value = 5 [default = FALSE]; + enum InitialValue { + UNKNOWN = 0; + FALSE = 1; + } + optional InitialValue initial_value = 5 [default = FALSE]; - optional FieldMatcher dimensions = 6; + optional FieldMatcher dimensions = 6; } message Predicate { - optional int64 id = 1; + optional int64 id = 1; - message Combination { - optional LogicalOperation operation = 1; + message Combination { + optional LogicalOperation operation = 1; - repeated int64 predicate = 2; - } + repeated int64 predicate = 2; + } - oneof contents { - SimplePredicate simple_predicate = 2; - Combination combination = 3; - } -} - -message Bucket { - optional int64 bucket_size_millis = 1; + oneof contents { + SimplePredicate simple_predicate = 2; + Combination combination = 3; + } } message MetricConditionLink { - optional int64 condition = 1; + optional int64 condition = 1; - optional FieldMatcher fields_in_what = 2; + optional FieldMatcher fields_in_what = 2; - optional FieldMatcher fields_in_condition = 3; + optional FieldMatcher fields_in_condition = 3; } message FieldFilter { - optional bool include_all = 1 [default = false]; - optional FieldMatcher fields = 2; + optional bool include_all = 1 [default = false]; + optional FieldMatcher fields = 2; } message EventMetric { - optional int64 id = 1; + optional int64 id = 1; - optional int64 what = 2; + optional int64 what = 2; - optional int64 condition = 3; + optional int64 condition = 3; - repeated MetricConditionLink links = 4; + repeated MetricConditionLink links = 4; } message CountMetric { - optional int64 id = 1; + optional int64 id = 1; - optional int64 what = 2; + optional int64 what = 2; - optional int64 condition = 3; + optional int64 condition = 3; - optional FieldMatcher dimensions_in_what = 4; + optional FieldMatcher dimensions_in_what = 4; - optional FieldMatcher dimensions_in_condition = 7; + optional FieldMatcher dimensions_in_condition = 7; - optional TimeUnit bucket = 5; + optional TimeUnit bucket = 5; - repeated MetricConditionLink links = 6; + repeated MetricConditionLink links = 6; } message DurationMetric { - optional int64 id = 1; + optional int64 id = 1; - optional int64 what = 2; + optional int64 what = 2; - optional int64 condition = 3; + optional int64 condition = 3; - repeated MetricConditionLink links = 4; + repeated MetricConditionLink links = 4; - enum AggregationType { - SUM = 1; + enum AggregationType { + SUM = 1; - MAX_SPARSE = 2; - } - optional AggregationType aggregation_type = 5 [default = SUM]; + MAX_SPARSE = 2; + } + optional AggregationType aggregation_type = 5 [default = SUM]; - optional FieldMatcher dimensions_in_what = 6; + optional FieldMatcher dimensions_in_what = 6; - optional FieldMatcher dimensions_in_condition = 8; + optional FieldMatcher dimensions_in_condition = 8; - optional TimeUnit bucket = 7; + optional TimeUnit bucket = 7; } message GaugeMetric { - optional int64 id = 1; + optional int64 id = 1; - optional int64 what = 2; + optional int64 what = 2; - optional FieldFilter gauge_fields_filter = 3; + optional FieldFilter gauge_fields_filter = 3; - optional int64 condition = 4; + optional int64 condition = 4; - optional FieldMatcher dimensions_in_what = 5; + optional FieldMatcher dimensions_in_what = 5; - optional FieldMatcher dimensions_in_condition = 8; + optional FieldMatcher dimensions_in_condition = 8; - optional TimeUnit bucket = 6; + optional TimeUnit bucket = 6; - repeated MetricConditionLink links = 7; + repeated MetricConditionLink links = 7; } message ValueMetric { - optional int64 id = 1; + optional int64 id = 1; - optional int64 what = 2; + optional int64 what = 2; - optional FieldMatcher value_field = 3; + optional FieldMatcher value_field = 3; - optional int64 condition = 4; + optional int64 condition = 4; - optional FieldMatcher dimensions_in_what = 5; + optional FieldMatcher dimensions_in_what = 5; - optional FieldMatcher dimensions_in_condition = 9; + optional FieldMatcher dimensions_in_condition = 9; - optional TimeUnit bucket = 6; + optional TimeUnit bucket = 6; - repeated MetricConditionLink links = 7; + repeated MetricConditionLink links = 7; - enum AggregationType { SUM = 1; } - optional AggregationType aggregation_type = 8 [default = SUM]; + enum AggregationType { + SUM = 1; + } + optional AggregationType aggregation_type = 8 [default = SUM]; } message Alert { - optional int64 id = 1; + optional int64 id = 1; - optional int64 metric_id = 2; + optional int64 metric_id = 2; - optional int32 num_buckets = 3; + optional int32 num_buckets = 3; - optional int32 refractory_period_secs = 4; + optional int32 refractory_period_secs = 4; - optional double trigger_if_sum_gt = 5; + optional double trigger_if_sum_gt = 5; } message Alarm { - optional int64 id = 1; - optional int64 offset_millis = 2; - optional int64 period_millis = 3; + optional int64 id = 1; + + optional int64 offset_millis = 2; + + optional int64 period_millis = 3; } message IncidentdDetails { - repeated int32 section = 1; + repeated int32 section = 1; } message PerfettoDetails { - optional perfetto.protos.TraceConfig trace_config = 1; + optional perfetto.protos.TraceConfig trace_config = 1; } -message Subscription { - optional int64 id = 1; - - enum RuleType { - RULE_TYPE_UNSPECIFIED = 0; - ALARM = 1; - ALERT = 2; - } - optional RuleType rule_type = 2; - - optional int64 rule_id = 3; +message BroadcastSubscriberDetails { + optional int64 subscriber_id = 1; +} - oneof subscriber_information { - IncidentdDetails incidentd_details = 4; - PerfettoDetails perfetto_details = 5; - } +message Subscription { + optional int64 id = 1; + + enum RuleType { + RULE_TYPE_UNSPECIFIED = 0; + ALARM = 1; + ALERT = 2; + } + optional RuleType rule_type = 2; + + optional int64 rule_id = 3; + + oneof subscriber_information { + IncidentdDetails incidentd_details = 4; + PerfettoDetails perfetto_details = 5; + BroadcastSubscriberDetails broadcast_subscriber_details = 6; + } } message StatsdConfig { - optional int64 id = 1; + optional int64 id = 1; - repeated EventMetric event_metric = 2; + repeated EventMetric event_metric = 2; - repeated CountMetric count_metric = 3; + repeated CountMetric count_metric = 3; - repeated ValueMetric value_metric = 4; + repeated ValueMetric value_metric = 4; - repeated GaugeMetric gauge_metric = 5; + repeated GaugeMetric gauge_metric = 5; - repeated DurationMetric duration_metric = 6; + repeated DurationMetric duration_metric = 6; - repeated AtomMatcher atom_matcher = 7; + repeated AtomMatcher atom_matcher = 7; - repeated Predicate predicate = 8; + repeated Predicate predicate = 8; - repeated Alert alert = 9; + repeated Alert alert = 9; - repeated Alarm alarm = 10; + repeated Alarm alarm = 10; - repeated Subscription subscription = 11; + repeated Subscription subscription = 11; - repeated string allowed_log_source = 12; + repeated string allowed_log_source = 12; - repeated int64 no_report_metric = 13; + repeated int64 no_report_metric = 13; } diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java index 843b1e5f90ac..2e0161be8096 100644 --- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java +++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.res.Resources; import android.util.Log; -import com.android.internal.os.StatsdConfigProto.Bucket; import com.android.internal.os.StatsdConfigProto.Predicate; import com.android.internal.os.StatsdConfigProto.CountMetric; import com.android.internal.os.StatsdConfigProto.DurationMetric; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 4048e6596cfc..49d522440fc4 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -222,9 +222,18 @@ public class ApplicationPackageManager extends PackageManager { @Override public Intent getLeanbackLaunchIntentForPackage(String packageName) { - // Try to find a main leanback_launcher activity. + return getLaunchIntentForPackageAndCategory(packageName, Intent.CATEGORY_LEANBACK_LAUNCHER); + } + + @Override + public Intent getCarLaunchIntentForPackage(String packageName) { + return getLaunchIntentForPackageAndCategory(packageName, Intent.CATEGORY_CAR_LAUNCHER); + } + + private Intent getLaunchIntentForPackageAndCategory(String packageName, String category) { + // Try to find a main launcher activity for the given categories. Intent intentToResolve = new Intent(Intent.ACTION_MAIN); - intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER); + intentToResolve.addCategory(category); intentToResolve.setPackage(packageName); List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 8b76cc7c966b..d6429ae9e540 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -867,19 +867,30 @@ public final class PendingIntent implements Parcelable { @Nullable OnFinished onFinished, @Nullable Handler handler, @Nullable String requiredPermission, @Nullable Bundle options) throws CanceledException { + if (sendAndReturnResult(context, code, intent, onFinished, handler, requiredPermission, + options) < 0) { + throw new CanceledException(); + } + } + + /** + * Like {@link #send}, but returns the result + * @hide + */ + public int sendAndReturnResult(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler, + @Nullable String requiredPermission, @Nullable Bundle options) + throws CanceledException { try { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) : null; - int res = ActivityManager.getService().sendIntentSender( + return ActivityManager.getService().sendIntentSender( mTarget, mWhitelistToken, code, intent, resolvedType, onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, requiredPermission, options); - if (res < 0) { - throw new CanceledException(); - } } catch (RemoteException e) { throw new CanceledException(e); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7fccda8c04e3..bad19e3bbb97 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8228,6 +8228,47 @@ public class DevicePolicyManager { } /** + * Called by a device or profile owner to restrict packages from accessing metered data. + * + * @param admin which {@link DeviceAdminReceiver} this request is associated with. + * @param packageNames the list of package names to be restricted. + * @return a list of package names which could not be restricted. + * @throws SecurityException if {@code admin} is not a device or profile owner. + */ + public @NonNull List<String> setMeteredDataDisabled(@NonNull ComponentName admin, + @NonNull List<String> packageNames) { + throwIfParentInstance("setMeteredDataDisabled"); + if (mService != null) { + try { + return mService.setMeteredDataDisabled(admin, packageNames); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + return packageNames; + } + + /** + * Called by a device or profile owner to retrieve the list of packages which are restricted + * by the admin from accessing metered data. + * + * @param admin which {@link DeviceAdminReceiver} this request is associated with. + * @return the list of restricted package names. + * @throws SecurityException if {@code admin} is not a device or profile owner. + */ + public @NonNull List<String> getMeteredDataDisabled(@NonNull ComponentName admin) { + throwIfParentInstance("getMeteredDataDisabled"); + if (mService != null) { + try { + return mService.getMeteredDataDisabled(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + return new ArrayList<>(); + } + + /** * Called by device owners to retrieve device logs from before the device's last reboot. * <p> * <strong> This API is not supported on all devices. Calling this API on unsupported devices diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index d2a2be7bbcb5..514dca92c816 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -400,4 +400,7 @@ interface IDevicePolicyManager { void setPrintingEnabled(in ComponentName admin, boolean enabled); boolean isPrintingEnabled(); CharSequence getPrintingDisabledReason(); + + List<String> setMeteredDataDisabled(in ComponentName admin, in List<String> packageNames); + List<String> getMeteredDataDisabled(in ComponentName admin); } diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java index 5bd3440d09f8..5808f8b510d9 100644 --- a/core/java/android/app/slice/Slice.java +++ b/core/java/android/app/slice/Slice.java @@ -156,10 +156,11 @@ public final class Slice implements Parcelable { */ public static final String HINT_SEE_MORE = "see_more"; /** - * A hint to tell the system that this slice cares about the return value of - * {@link SliceProvider#getBindingPackage} and should not cache the result - * for multiple apps. - * @hide + * A hint used when implementing app-specific slice permissions. + * Tells the system that for this slice the return value of + * {@link SliceProvider#onBindSlice(Uri, List)} may be different depending on + * {@link SliceProvider#getBindingPackage} and should not be cached for multiple + * apps. */ public static final String HINT_CALLER_NEEDED = "caller_needed"; /** @@ -429,28 +430,6 @@ public final class Slice implements Parcelable { * Add a color to the slice being constructed * @param subType Optional template-specific type information * @see {@link SliceItem#getSubType()} - * @deprecated will be removed once supportlib updates - */ - public Builder addColor(int color, @Nullable String subType, @SliceHint String... hints) { - mItems.add(new SliceItem(color, SliceItem.FORMAT_INT, subType, hints)); - return this; - } - - /** - * Add a color to the slice being constructed - * @param subType Optional template-specific type information - * @see {@link SliceItem#getSubType()} - * @deprecated will be removed once supportlib updates - */ - public Builder addColor(int color, @Nullable String subType, - @SliceHint List<String> hints) { - return addColor(color, subType, hints.toArray(new String[hints.size()])); - } - - /** - * Add a color to the slice being constructed - * @param subType Optional template-specific type information - * @see {@link SliceItem#getSubType()} */ public Builder addInt(int value, @Nullable String subType, @SliceHint String... hints) { mItems.add(new SliceItem(value, SliceItem.FORMAT_INT, subType, hints)); diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java index bcfd413fb823..9eb2bb896356 100644 --- a/core/java/android/app/slice/SliceItem.java +++ b/core/java/android/app/slice/SliceItem.java @@ -98,11 +98,6 @@ public final class SliceItem implements Parcelable { */ public static final String FORMAT_INT = "int"; /** - * A {@link SliceItem} that contains an int. - * @deprecated to be removed - */ - public static final String FORMAT_COLOR = "color"; - /** * A {@link SliceItem} that contains a timestamp. */ public static final String FORMAT_TIMESTAMP = "timestamp"; @@ -231,13 +226,6 @@ public final class SliceItem implements Parcelable { } /** - * @deprecated to be removed. - */ - public int getColor() { - return (Integer) mObj; - } - - /** * @return The slice held by this {@link #FORMAT_ACTION} or {@link #FORMAT_SLICE} SliceItem */ public Slice getSlice() { diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd4103f60ac6..00e8ccad0f5f 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -158,7 +158,6 @@ public abstract class SliceProvider extends ContentProvider { * currently happening. The returned package will have been * verified to belong to the calling UID. Returns {@code null} if not * currently performing an {@link #onBindSlice(Uri, List)}. - * @hide */ public final @Nullable String getBindingPackage() { return mBindingPkg; diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java index 16309fab0924..e86d348a85fa 100644 --- a/core/java/android/app/timezone/RulesState.java +++ b/core/java/android/app/timezone/RulesState.java @@ -126,9 +126,6 @@ public final class RulesState implements Parcelable { mStagedOperationType == STAGED_OPERATION_INSTALL /* requireNotNull */, "stagedDistroRulesVersion", stagedDistroRulesVersion); - if (operationInProgress && distroStatus != DISTRO_STATUS_UNKNOWN) { - throw new IllegalArgumentException("distroInstalled != DISTRO_STATUS_UNKNOWN"); - } this.mDistroStatus = validateDistroStatus(distroStatus); this.mInstalledDistroRulesVersion = validateConditionalNull( mDistroStatus == DISTRO_STATUS_INSTALLED/* requireNotNull */, diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index ef1bcb0dcf9a..acbdf142c62d 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3930,6 +3930,14 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER"; /** + * Indicates the preferred entry-point activity when an application is launched from a Car + * launcher. If not present, Car launcher can optionally use {@link #CATEGORY_LAUNCHER} as a + * fallback, or exclude the application entirely. + * @hide + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_CAR_LAUNCHER = "android.intent.category.CAR_LAUNCHER"; + /** * Indicates a Leanback settings activity to be displayed in the Leanback launcher. * @hide */ diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bcf80eeaaee7..b81267ab46f9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3044,6 +3044,21 @@ public abstract class PackageManager { public abstract @Nullable Intent getLeanbackLaunchIntentForPackage(@NonNull String packageName); /** + * Return a "good" intent to launch a front-door Car activity in a + * package, for use for example to implement an "open" button when browsing + * through packages. The current implementation will look for a main + * activity in the category {@link Intent#CATEGORY_CAR_LAUNCHER}, or + * return null if no main car activities are found. + * + * @param packageName The name of the package to inspect. + * @return Returns either a fully-qualified Intent that can be used to launch + * the main Car activity in the package, or null if the package + * does not contain such an activity. + * @hide + */ + public abstract @Nullable Intent getCarLaunchIntentForPackage(@NonNull String packageName); + + /** * Return an array of all of the POSIX secondary group IDs that have been * assigned to the given package. * <p> diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4a71467f4b36..4efd08134065 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -5684,23 +5684,74 @@ public class PackageParser { @Nullable public final ArraySet<PublicKey> publicKeys; + /** + * Collection of {@code Signature} objects, each of which is formed from a former signing + * certificate of this APK before it was changed by signing certificate rotation. + */ + @Nullable + public final Signature[] pastSigningCertificates; + + /** + * Flags for the {@code pastSigningCertificates} collection, which indicate the capabilities + * the including APK wishes to grant to its past signing certificates. + */ + @Nullable + public final int[] pastSigningCertificatesFlags; + /** A representation of unknown signing details. Use instead of null. */ public static final SigningDetails UNKNOWN = - new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null); + new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null, null, null); @VisibleForTesting public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, - ArraySet<PublicKey> keys) { + ArraySet<PublicKey> keys, Signature[] pastSigningCertificates, + int[] pastSigningCertificatesFlags) { this.signatures = signatures; this.signatureSchemeVersion = signatureSchemeVersion; this.publicKeys = keys; + this.pastSigningCertificates = pastSigningCertificates; + this.pastSigningCertificatesFlags = pastSigningCertificatesFlags; + } + + public SigningDetails(Signature[] signatures, + @SignatureSchemeVersion int signatureSchemeVersion, + Signature[] pastSigningCertificates, int[] pastSigningCertificatesFlags) + throws CertificateException { + this(signatures, signatureSchemeVersion, toSigningKeys(signatures), + pastSigningCertificates, pastSigningCertificatesFlags); } public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion) throws CertificateException { - this(signatures, signatureSchemeVersion, toSigningKeys(signatures)); + this(signatures, signatureSchemeVersion, + null, null); + } + + public SigningDetails(SigningDetails orig) { + if (orig != null) { + if (orig.signatures != null) { + this.signatures = orig.signatures.clone(); + } else { + this.signatures = null; + } + this.signatureSchemeVersion = orig.signatureSchemeVersion; + this.publicKeys = new ArraySet<>(orig.publicKeys); + if (orig.pastSigningCertificates != null) { + this.pastSigningCertificates = orig.pastSigningCertificates.clone(); + this.pastSigningCertificatesFlags = orig.pastSigningCertificatesFlags.clone(); + } else { + this.pastSigningCertificates = null; + this.pastSigningCertificatesFlags = null; + } + } else { + this.signatures = null; + this.signatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; + this.publicKeys = null; + this.pastSigningCertificates = null; + this.pastSigningCertificatesFlags = null; + } } /** Returns true if the signing details have one or more signatures. */ @@ -5728,6 +5779,8 @@ public class PackageParser { dest.writeTypedArray(this.signatures, flags); dest.writeInt(this.signatureSchemeVersion); dest.writeArraySet(this.publicKeys); + dest.writeTypedArray(this.pastSigningCertificates, flags); + dest.writeIntArray(this.pastSigningCertificatesFlags); } protected SigningDetails(Parcel in) { @@ -5735,6 +5788,8 @@ public class PackageParser { this.signatures = in.createTypedArray(Signature.CREATOR); this.signatureSchemeVersion = in.readInt(); this.publicKeys = (ArraySet<PublicKey>) in.readArraySet(boot); + this.pastSigningCertificates = in.createTypedArray(Signature.CREATOR); + this.pastSigningCertificatesFlags = in.createIntArray(); } public static final Creator<SigningDetails> CREATOR = new Creator<SigningDetails>() { @@ -5761,8 +5816,23 @@ public class PackageParser { if (signatureSchemeVersion != that.signatureSchemeVersion) return false; if (!Signature.areExactMatch(signatures, that.signatures)) return false; - return publicKeys != null ? publicKeys.equals(that.publicKeys) - : that.publicKeys == null; + if (publicKeys != null) { + if (!publicKeys.equals((that.publicKeys))) { + return false; + } + } else if (that.publicKeys != null) { + return false; + } + + // can't use Signature.areExactMatch() because order matters with the past signing certs + if (!Arrays.equals(pastSigningCertificates, that.pastSigningCertificates)) { + return false; + } + if (!Arrays.equals(pastSigningCertificatesFlags, that.pastSigningCertificatesFlags)) { + return false; + } + + return true; } @Override @@ -5770,8 +5840,77 @@ public class PackageParser { int result = +Arrays.hashCode(signatures); result = 31 * result + signatureSchemeVersion; result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); + result = 31 * result + Arrays.hashCode(pastSigningCertificates); + result = 31 * result + Arrays.hashCode(pastSigningCertificatesFlags); return result; } + + /** + * Builder of {@code SigningDetails} instances. + */ + public static class Builder { + private Signature[] mSignatures; + private int mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; + private Signature[] mPastSigningCertificates; + private int[] mPastSigningCertificatesFlags; + + public Builder() { + } + + /** get signing certificates used to sign the current APK */ + public Builder setSignatures(Signature[] signatures) { + mSignatures = signatures; + return this; + } + + /** set the signature scheme version used to sign the APK */ + public Builder setSignatureSchemeVersion(int signatureSchemeVersion) { + mSignatureSchemeVersion = signatureSchemeVersion; + return this; + } + + /** set the signing certificates by which the APK proved it can be authenticated */ + public Builder setPastSigningCertificates(Signature[] pastSigningCertificates) { + mPastSigningCertificates = pastSigningCertificates; + return this; + } + + /** set the flags for the {@code pastSigningCertificates} */ + public Builder setPastSigningCertificatesFlags(int[] pastSigningCertificatesFlags) { + mPastSigningCertificatesFlags = pastSigningCertificatesFlags; + return this; + } + + private void checkInvariants() { + // must have signatures and scheme version set + if (mSignatures == null) { + throw new IllegalStateException("SigningDetails requires the current signing" + + " certificates."); + } + + // pastSigningCerts and flags must match up + boolean pastMismatch = false; + if (mPastSigningCertificates != null && mPastSigningCertificatesFlags != null) { + if (mPastSigningCertificates.length != mPastSigningCertificatesFlags.length) { + pastMismatch = true; + } + } else if (!(mPastSigningCertificates == null + && mPastSigningCertificatesFlags == null)) { + pastMismatch = true; + } + if (pastMismatch) { + throw new IllegalStateException("SigningDetails must have a one to one mapping " + + "between pastSigningCertificates and pastSigningCertificatesFlags"); + } + } + /** build a {@code SigningDetails} object */ + public SigningDetails build() + throws CertificateException { + checkInvariants(); + return new SigningDetails(mSignatures, mSignatureSchemeVersion, + mPastSigningCertificates, mPastSigningCertificatesFlags); + } + } } /** diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 7654e9b6ee22..76838807acc5 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -143,7 +143,7 @@ public class Process { * Defines the UID/GID for the WebView zygote process. * @hide */ - public static final int WEBVIEW_ZYGOTE_UID = 1051; + public static final int WEBVIEW_ZYGOTE_UID = 1053; /** * Defines the UID used for resource tracking for OTA updates. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0e323f8570a0..228a86d40463 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -41,7 +41,6 @@ import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.Application; import android.app.NotificationChannel; -import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.app.SearchManager; import android.app.WallpaperManager; @@ -75,7 +74,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.UserHandle; -import android.provider.SettingsValidators; import android.provider.SettingsValidators.Validator; import android.speech.tts.TextToSpeech; import android.telephony.SubscriptionManager; @@ -1345,18 +1343,6 @@ public final class Settings { = "android.settings.CHANNEL_NOTIFICATION_SETTINGS"; /** - * Activity Action: Show notification settings for a single {@link NotificationChannelGroup}. - * <p> - * Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel group to display. - * Input: {@link #EXTRA_CHANNEL_GROUP_ID}, the id of the channel group to display. - * <p> - * Output: Nothing. - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS = - "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS"; - - /** * Activity Extra: The package owner of the notification channel settings to display. * <p> * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}. @@ -1372,15 +1358,6 @@ public final class Settings { public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID"; /** - * Activity Extra: The {@link NotificationChannelGroup#getId()} of the notification channel - * group settings to display. - * <p> - * This must be passed as an extra field to the - * {@link #ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS}. - */ - public static final String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID"; - - /** * Activity Action: Show notification redaction settings. * * @hide diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 72afbb8414f6..346437032845 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -102,6 +102,7 @@ public final class KeymasterDefs { public static final int KM_ALGORITHM_RSA = 1; public static final int KM_ALGORITHM_EC = 3; public static final int KM_ALGORITHM_AES = 32; + public static final int KM_ALGORITHM_3DES = 33; public static final int KM_ALGORITHM_HMAC = 128; // Block modes. @@ -131,6 +132,7 @@ public final class KeymasterDefs { public static final int KM_ORIGIN_GENERATED = 0; public static final int KM_ORIGIN_IMPORTED = 2; public static final int KM_ORIGIN_UNKNOWN = 3; + public static final int KM_ORIGIN_SECURELY_IMPORTED = 4; // Key usability requirements. public static final int KM_BLOB_STANDALONE = 0; @@ -141,6 +143,7 @@ public final class KeymasterDefs { public static final int KM_PURPOSE_DECRYPT = 1; public static final int KM_PURPOSE_SIGN = 2; public static final int KM_PURPOSE_VERIFY = 3; + public static final int KM_PURPOSE_WRAP = 5; // Key formats. public static final int KM_KEY_FORMAT_X509 = 0; diff --git a/core/java/android/security/keystore/BackwardsCompat.java b/core/java/android/security/keystore/BackwardsCompat.java new file mode 100644 index 000000000000..24921f03f136 --- /dev/null +++ b/core/java/android/security/keystore/BackwardsCompat.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * Helpers for converting classes between old and new API, so we can preserve backwards + * compatibility while teamfooding. This will be removed soon. + * + * @hide + */ +class BackwardsCompat { + + + static KeychainProtectionParams toLegacyKeychainProtectionParams( + android.security.keystore.recovery.KeychainProtectionParams keychainProtectionParams + ) { + return new KeychainProtectionParams.Builder() + .setUserSecretType(keychainProtectionParams.getUserSecretType()) + .setSecret(keychainProtectionParams.getSecret()) + .setLockScreenUiFormat(keychainProtectionParams.getLockScreenUiFormat()) + .setKeyDerivationParams( + toLegacyKeyDerivationParams( + keychainProtectionParams.getKeyDerivationParams())) + .build(); + } + + static KeyDerivationParams toLegacyKeyDerivationParams( + android.security.keystore.recovery.KeyDerivationParams keyDerivationParams + ) { + return new KeyDerivationParams( + keyDerivationParams.getAlgorithm(), keyDerivationParams.getSalt()); + } + + static WrappedApplicationKey toLegacyWrappedApplicationKey( + android.security.keystore.recovery.WrappedApplicationKey wrappedApplicationKey + ) { + return new WrappedApplicationKey.Builder() + .setAlias(wrappedApplicationKey.getAlias()) + .setEncryptedKeyMaterial(wrappedApplicationKey.getEncryptedKeyMaterial()) + .build(); + } + + static android.security.keystore.recovery.KeyDerivationParams fromLegacyKeyDerivationParams( + KeyDerivationParams keyDerivationParams + ) { + return new android.security.keystore.recovery.KeyDerivationParams( + keyDerivationParams.getAlgorithm(), keyDerivationParams.getSalt()); + } + + static android.security.keystore.recovery.WrappedApplicationKey fromLegacyWrappedApplicationKey( + WrappedApplicationKey wrappedApplicationKey + ) { + return new android.security.keystore.recovery.WrappedApplicationKey.Builder() + .setAlias(wrappedApplicationKey.getAlias()) + .setEncryptedKeyMaterial(wrappedApplicationKey.getEncryptedKeyMaterial()) + .build(); + } + + static List<android.security.keystore.recovery.WrappedApplicationKey> + fromLegacyWrappedApplicationKeys(List<WrappedApplicationKey> wrappedApplicationKeys + ) { + return map(wrappedApplicationKeys, BackwardsCompat::fromLegacyWrappedApplicationKey); + } + + static List<android.security.keystore.recovery.KeychainProtectionParams> + fromLegacyKeychainProtectionParams( + List<KeychainProtectionParams> keychainProtectionParams) { + return map(keychainProtectionParams, BackwardsCompat::fromLegacyKeychainProtectionParam); + } + + static android.security.keystore.recovery.KeychainProtectionParams + fromLegacyKeychainProtectionParam(KeychainProtectionParams keychainProtectionParams) { + return new android.security.keystore.recovery.KeychainProtectionParams.Builder() + .setUserSecretType(keychainProtectionParams.getUserSecretType()) + .setSecret(keychainProtectionParams.getSecret()) + .setLockScreenUiFormat(keychainProtectionParams.getLockScreenUiFormat()) + .setKeyDerivationParams( + fromLegacyKeyDerivationParams( + keychainProtectionParams.getKeyDerivationParams())) + .build(); + } + + static KeychainSnapshot toLegacyKeychainSnapshot( + android.security.keystore.recovery.KeychainSnapshot keychainSnapshot + ) { + return new KeychainSnapshot.Builder() + .setCounterId(keychainSnapshot.getCounterId()) + .setEncryptedRecoveryKeyBlob(keychainSnapshot.getEncryptedRecoveryKeyBlob()) + .setTrustedHardwarePublicKey(keychainSnapshot.getTrustedHardwarePublicKey()) + .setSnapshotVersion(keychainSnapshot.getSnapshotVersion()) + .setMaxAttempts(keychainSnapshot.getMaxAttempts()) + .setServerParams(keychainSnapshot.getServerParams()) + .setKeychainProtectionParams( + map(keychainSnapshot.getKeychainProtectionParams(), + BackwardsCompat::toLegacyKeychainProtectionParams)) + .setWrappedApplicationKeys( + map(keychainSnapshot.getWrappedApplicationKeys(), + BackwardsCompat::toLegacyWrappedApplicationKey)) + .build(); + } + + static <A, B> List<B> map(List<A> as, Function<A, B> f) { + ArrayList<B> bs = new ArrayList<>(as.size()); + for (A a : as) { + bs.add(f.apply(a)); + } + return bs; + } +} diff --git a/core/java/android/security/keystore/KeyDerivationParams.java b/core/java/android/security/keystore/KeyDerivationParams.java index b702accffba1..b19cee2d31a4 100644 --- a/core/java/android/security/keystore/KeyDerivationParams.java +++ b/core/java/android/security/keystore/KeyDerivationParams.java @@ -61,7 +61,7 @@ public final class KeyDerivationParams implements Parcelable { return new KeyDerivationParams(ALGORITHM_SHA256, salt); } - private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { + KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { mAlgorithm = algorithm; mSalt = Preconditions.checkNotNull(salt); } diff --git a/core/java/android/security/keystore/RecoveryController.java b/core/java/android/security/keystore/RecoveryController.java index 87283cbd75ab..8be6d5263c53 100644 --- a/core/java/android/security/keystore/RecoveryController.java +++ b/core/java/android/security/keystore/RecoveryController.java @@ -167,7 +167,7 @@ public class RecoveryController { public @NonNull KeychainSnapshot getRecoveryData(@NonNull byte[] account) throws InternalRecoveryServiceException { try { - return mBinder.getRecoveryData(account); + return BackwardsCompat.toLegacyKeychainSnapshot(mBinder.getRecoveryData(account)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { @@ -360,28 +360,6 @@ public class RecoveryController { } /** - * Method notifies KeyStore that a user-generated secret is available. This method generates a - * symmetric session key which a trusted remote device can use to return a recovery key. Caller - * should use {@link KeychainProtectionParams#clearSecret} to override the secret value in - * memory. - * - * @param recoverySecret user generated secret together with parameters necessary to regenerate - * it on a new device. - * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery - * service. - */ - public void recoverySecretAvailable(@NonNull KeychainProtectionParams recoverySecret) - throws InternalRecoveryServiceException { - try { - mBinder.recoverySecretAvailable(recoverySecret); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - throw wrapUnexpectedServiceSpecificException(e); - } - } - - /** * Initializes recovery session and returns a blob with proof of recovery secrets possession. * The method generates symmetric key for a session, which trusted remote device can use to * return recovery key. @@ -417,7 +395,7 @@ public class RecoveryController { verifierPublicKey, vaultParams, vaultChallenge, - secrets); + BackwardsCompat.fromLegacyKeychainProtectionParams(secrets)); return new RecoveryClaim(recoverySession, recoveryClaim); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -451,7 +429,9 @@ public class RecoveryController { InternalRecoveryServiceException { try { return (Map<String, byte[]>) mBinder.recoverKeys( - session.getSessionId(), recoveryKeyBlob, applicationKeys); + session.getSessionId(), + recoveryKeyBlob, + BackwardsCompat.fromLegacyWrappedApplicationKeys(applicationKeys)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { diff --git a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java new file mode 100644 index 000000000000..fda3387bb63b --- /dev/null +++ b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * Error thrown when the recovery agent supplies an invalid X509 certificate. + * + * @hide + */ +public class BadCertificateFormatException extends RecoveryControllerException { + public BadCertificateFormatException(String msg) { + super(msg); + } +} diff --git a/core/java/android/security/keystore/recovery/DecryptionFailedException.java b/core/java/android/security/keystore/recovery/DecryptionFailedException.java new file mode 100644 index 000000000000..b414dc59834b --- /dev/null +++ b/core/java/android/security/keystore/recovery/DecryptionFailedException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * Error thrown when decryption failed, due to an agent error. i.e., using the incorrect key, + * trying to decrypt garbage data, trying to decrypt data that has somehow been corrupted, etc. + * + * @hide + */ +public class DecryptionFailedException extends RecoveryControllerException { + + public DecryptionFailedException(String msg) { + super(msg); + } +} diff --git a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java new file mode 100644 index 000000000000..07a540ceea25 --- /dev/null +++ b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * An error thrown when something went wrong internally in the recovery service. + * + * <p>This is an unexpected error, and indicates a problem with the service itself, rather than the + * caller having performed some kind of illegal action. + * + * @hide + */ +public class InternalRecoveryServiceException extends RecoveryControllerException { + public InternalRecoveryServiceException(String msg) { + super(msg); + } + + public InternalRecoveryServiceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/core/java/android/security/keystore/KeyDerivationParams.aidl b/core/java/android/security/keystore/recovery/KeyDerivationParams.aidl index f39aa047adee..2b1bbbe35f1a 100644 --- a/core/java/android/security/keystore/KeyDerivationParams.aidl +++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.keystore; +package android.security.keystore.recovery; /* @hide */ parcelable KeyDerivationParams; diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java new file mode 100644 index 000000000000..90613952ae9b --- /dev/null +++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Collection of parameters which define a key derivation function. + * Currently only supports salted SHA-256 + * + * @hide + */ +public final class KeyDerivationParams implements Parcelable { + private final int mAlgorithm; + private byte[] mSalt; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) + public @interface KeyDerivationAlgorithm { + } + + /** + * Salted SHA256 + */ + public static final int ALGORITHM_SHA256 = 1; + + /** + * Argon2ID + * @hide + */ + // TODO: add Argon2ID support. + public static final int ALGORITHM_ARGON2ID = 2; + + /** + * Creates instance of the class to to derive key using salted SHA256 hash. + */ + public static KeyDerivationParams createSha256Params(@NonNull byte[] salt) { + return new KeyDerivationParams(ALGORITHM_SHA256, salt); + } + + // TODO: Make private once legacy API is removed + public KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { + mAlgorithm = algorithm; + mSalt = Preconditions.checkNotNull(salt); + } + + /** + * Gets algorithm. + */ + public @KeyDerivationAlgorithm int getAlgorithm() { + return mAlgorithm; + } + + /** + * Gets salt. + */ + public @NonNull byte[] getSalt() { + return mSalt; + } + + public static final Creator<KeyDerivationParams> CREATOR = + new Creator<KeyDerivationParams>() { + public KeyDerivationParams createFromParcel(Parcel in) { + return new KeyDerivationParams(in); + } + + public KeyDerivationParams[] newArray(int length) { + return new KeyDerivationParams[length]; + } + }; + + /** + * @hide + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mAlgorithm); + out.writeByteArray(mSalt); + } + + /** + * @hide + */ + protected KeyDerivationParams(Parcel in) { + mAlgorithm = in.readInt(); + mSalt = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/security/keystore/KeychainProtectionParams.aidl b/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl index 0341223b081a..538573847b00 100644 --- a/core/java/android/security/keystore/KeychainProtectionParams.aidl +++ b/core/java/android/security/keystore/recovery/KeychainProtectionParams.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.keystore; +package android.security.keystore.recovery; /* @hide */ parcelable KeychainProtectionParams; diff --git a/core/java/android/security/keystore/recovery/KeychainProtectionParams.java b/core/java/android/security/keystore/recovery/KeychainProtectionParams.java new file mode 100644 index 000000000000..445815b48e7c --- /dev/null +++ b/core/java/android/security/keystore/recovery/KeychainProtectionParams.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * A {@link KeychainSnapshot} is protected with a key derived from the user's lock screen. This + * class wraps all the data necessary to derive the same key on a recovering device: + * + * <ul> + * <li>UI parameters for the user's lock screen - so that if e.g., the user was using a pattern, + * the recovering device can display the pattern UI to the user when asking them to enter + * the lock screen from their previous device. + * <li>The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt. + * </ul> + * + * <p>As such, this data is sent along with the {@link KeychainSnapshot} when syncing the current + * version of the keychain. + * + * <p>For now, the recoverable keychain only supports a single layer of protection, which is the + * user's lock screen. In the future, the keychain will support multiple layers of protection + * (e.g. an additional keychain password, along with the lock screen). + * + * @hide + */ +public final class KeychainProtectionParams implements Parcelable { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD}) + public @interface UserSecretType { + } + + /** + * Lockscreen secret is required to recover KeyStore. + */ + public static final int TYPE_LOCKSCREEN = 100; + + /** + * Custom passphrase, unrelated to lock screen, is required to recover KeyStore. + */ + public static final int TYPE_CUSTOM_PASSWORD = 101; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({TYPE_PIN, TYPE_PASSWORD, TYPE_PATTERN}) + public @interface LockScreenUiFormat { + } + + /** + * Pin with digits only. + */ + public static final int TYPE_PIN = 1; + + /** + * Password. String with latin-1 characters only. + */ + public static final int TYPE_PASSWORD = 2; + + /** + * Pattern with 3 by 3 grid. + */ + public static final int TYPE_PATTERN = 3; + + @UserSecretType + private Integer mUserSecretType; + + @LockScreenUiFormat + private Integer mLockScreenUiFormat; + + /** + * Parameters of the key derivation function, including algorithm, difficulty, salt. + */ + private KeyDerivationParams mKeyDerivationParams; + private byte[] mSecret; // Derived from user secret. The field must have limited visibility. + + /** + * @param secret Constructor creates a reference to the secret. Caller must use + * @link {#clearSecret} to overwrite its value in memory. + * @hide + */ + public KeychainProtectionParams(@UserSecretType int userSecretType, + @LockScreenUiFormat int lockScreenUiFormat, + @NonNull KeyDerivationParams keyDerivationParams, + @NonNull byte[] secret) { + mUserSecretType = userSecretType; + mLockScreenUiFormat = lockScreenUiFormat; + mKeyDerivationParams = Preconditions.checkNotNull(keyDerivationParams); + mSecret = Preconditions.checkNotNull(secret); + } + + private KeychainProtectionParams() { + + } + + /** + * @see TYPE_LOCKSCREEN + * @see TYPE_CUSTOM_PASSWORD + */ + public @UserSecretType int getUserSecretType() { + return mUserSecretType; + } + + /** + * Specifies UX shown to user during recovery. + * Default value is {@code TYPE_LOCKSCREEN} + * + * @see TYPE_PIN + * @see TYPE_PASSWORD + * @see TYPE_PATTERN + */ + public @LockScreenUiFormat int getLockScreenUiFormat() { + return mLockScreenUiFormat; + } + + /** + * Specifies function used to derive symmetric key from user input + * Format is defined in separate util class. + */ + @NonNull public KeyDerivationParams getKeyDerivationParams() { + return mKeyDerivationParams; + } + + /** + * Secret derived from user input. + * Default value is empty array + * + * @return secret or empty array + */ + public @NonNull byte[] getSecret() { + return mSecret; + } + + /** + * Builder for creating {@link KeychainProtectionParams}. + */ + public static class Builder { + private KeychainProtectionParams + mInstance = new KeychainProtectionParams(); + + /** + * Sets user secret type. + * + * @see TYPE_LOCKSCREEN + * @see TYPE_CUSTOM_PASSWORD + * @param userSecretType The secret type + * @return This builder. + */ + public Builder setUserSecretType(@UserSecretType int userSecretType) { + mInstance.mUserSecretType = userSecretType; + return this; + } + + /** + * Sets UI format. + * + * @see TYPE_PIN + * @see TYPE_PASSWORD + * @see TYPE_PATTERN + * @param lockScreenUiFormat The UI format + * @return This builder. + */ + public Builder setLockScreenUiFormat(@LockScreenUiFormat int lockScreenUiFormat) { + mInstance.mLockScreenUiFormat = lockScreenUiFormat; + return this; + } + + /** + * Sets parameters of the key derivation function. + * + * @param keyDerivationParams Key derivation Params + * @return This builder. + */ + public Builder setKeyDerivationParams(@NonNull KeyDerivationParams + keyDerivationParams) { + mInstance.mKeyDerivationParams = keyDerivationParams; + return this; + } + + /** + * Secret derived from user input, or empty array. + * + * @param secret The secret. + * @return This builder. + */ + public Builder setSecret(@NonNull byte[] secret) { + mInstance.mSecret = secret; + return this; + } + + + /** + * Creates a new {@link KeychainProtectionParams} instance. + * The instance will include default values, if {@link setSecret} + * or {@link setUserSecretType} were not called. + * + * @return new instance + * @throws NullPointerException if some required fields were not set. + */ + @NonNull public KeychainProtectionParams build() { + if (mInstance.mUserSecretType == null) { + mInstance.mUserSecretType = TYPE_LOCKSCREEN; + } + Preconditions.checkNotNull(mInstance.mLockScreenUiFormat); + Preconditions.checkNotNull(mInstance.mKeyDerivationParams); + if (mInstance.mSecret == null) { + mInstance.mSecret = new byte[]{}; + } + return mInstance; + } + } + + /** + * Removes secret from memory than object is no longer used. + * Since finalizer call is not reliable, please use @link {#clearSecret} directly. + */ + @Override + protected void finalize() throws Throwable { + clearSecret(); + super.finalize(); + } + + /** + * Fills mSecret with zeroes. + */ + public void clearSecret() { + Arrays.fill(mSecret, (byte) 0); + } + + public static final Creator<KeychainProtectionParams> CREATOR = + new Creator<KeychainProtectionParams>() { + public KeychainProtectionParams createFromParcel(Parcel in) { + return new KeychainProtectionParams(in); + } + + public KeychainProtectionParams[] newArray(int length) { + return new KeychainProtectionParams[length]; + } + }; + + /** + * @hide + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mUserSecretType); + out.writeInt(mLockScreenUiFormat); + out.writeTypedObject(mKeyDerivationParams, flags); + out.writeByteArray(mSecret); + } + + /** + * @hide + */ + protected KeychainProtectionParams(Parcel in) { + mUserSecretType = in.readInt(); + mLockScreenUiFormat = in.readInt(); + mKeyDerivationParams = in.readTypedObject(KeyDerivationParams.CREATOR); + mSecret = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/security/keystore/KeychainSnapshot.aidl b/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl index b35713f329d6..7822f39bf269 100644 --- a/core/java/android/security/keystore/KeychainSnapshot.aidl +++ b/core/java/android/security/keystore/recovery/KeychainSnapshot.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.keystore; +package android.security.keystore.recovery; /* @hide */ parcelable KeychainSnapshot; diff --git a/core/java/android/security/keystore/recovery/KeychainSnapshot.java b/core/java/android/security/keystore/recovery/KeychainSnapshot.java new file mode 100644 index 000000000000..a8e2725c0339 --- /dev/null +++ b/core/java/android/security/keystore/recovery/KeychainSnapshot.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.List; + +/** + * A snapshot of a version of the keystore. Two events can trigger the generation of a new snapshot: + * + * <ul> + * <li>The user's lock screen changes. (A key derived from the user's lock screen is used to + * protected the keychain, which is why this forces a new snapshot.) + * <li>A key is added to or removed from the recoverable keychain. + * </ul> + * + * <p>The snapshot data is also encrypted with the remote trusted hardware's public key, so even + * the recovery agent itself should not be able to decipher the data. The recovery agent sends an + * instance of this to the remote trusted hardware whenever a new snapshot is generated. During a + * recovery flow, the recovery agent retrieves a snapshot from the remote trusted hardware. It then + * sends it to the framework, where it is decrypted using the user's lock screen from their previous + * device. + * + * @hide + */ +public final class KeychainSnapshot implements Parcelable { + private static final int DEFAULT_MAX_ATTEMPTS = 10; + private static final long DEFAULT_COUNTER_ID = 1L; + + private int mSnapshotVersion; + private int mMaxAttempts = DEFAULT_MAX_ATTEMPTS; + private long mCounterId = DEFAULT_COUNTER_ID; + private byte[] mServerParams; + private byte[] mPublicKey; + private List<KeychainProtectionParams> mKeychainProtectionParams; + private List<WrappedApplicationKey> mEntryRecoveryData; + private byte[] mEncryptedRecoveryKeyBlob; + + /** + * @hide + * Deprecated, consider using builder. + */ + public KeychainSnapshot( + int snapshotVersion, + @NonNull List<KeychainProtectionParams> keychainProtectionParams, + @NonNull List<WrappedApplicationKey> wrappedApplicationKeys, + @NonNull byte[] encryptedRecoveryKeyBlob) { + mSnapshotVersion = snapshotVersion; + mKeychainProtectionParams = + Preconditions.checkCollectionElementsNotNull(keychainProtectionParams, + "keychainProtectionParams"); + mEntryRecoveryData = Preconditions.checkCollectionElementsNotNull(wrappedApplicationKeys, + "wrappedApplicationKeys"); + mEncryptedRecoveryKeyBlob = Preconditions.checkNotNull(encryptedRecoveryKeyBlob); + } + + private KeychainSnapshot() { + + } + + /** + * Snapshot version for given account. It is incremented when user secret or list of application + * keys changes. + */ + public int getSnapshotVersion() { + return mSnapshotVersion; + } + + /** + * Number of user secret guesses allowed during Keychain recovery. + */ + public int getMaxAttempts() { + return mMaxAttempts; + } + + /** + * CounterId which is rotated together with user secret. + */ + public long getCounterId() { + return mCounterId; + } + + /** + * Server parameters. + */ + public @NonNull byte[] getServerParams() { + return mServerParams; + } + + /** + * Public key used to encrypt {@code encryptedRecoveryKeyBlob}. + * + * See implementation for binary key format + */ + // TODO: document key format. + public @NonNull byte[] getTrustedHardwarePublicKey() { + return mPublicKey; + } + + /** + * UI and key derivation parameters. Note that combination of secrets may be used. + */ + public @NonNull List<KeychainProtectionParams> getKeychainProtectionParams() { + return mKeychainProtectionParams; + } + + /** + * List of application keys, with key material encrypted by + * the recovery key ({@link #getEncryptedRecoveryKeyBlob}). + */ + public @NonNull List<WrappedApplicationKey> getWrappedApplicationKeys() { + return mEntryRecoveryData; + } + + /** + * Recovery key blob, encrypted by user secret and recovery service public key. + */ + public @NonNull byte[] getEncryptedRecoveryKeyBlob() { + return mEncryptedRecoveryKeyBlob; + } + + public static final Creator<KeychainSnapshot> CREATOR = + new Creator<KeychainSnapshot>() { + public KeychainSnapshot createFromParcel(Parcel in) { + return new KeychainSnapshot(in); + } + + public KeychainSnapshot[] newArray(int length) { + return new KeychainSnapshot[length]; + } + }; + + /** + * Builder for creating {@link KeychainSnapshot}. + */ + public static class Builder { + private KeychainSnapshot + mInstance = new KeychainSnapshot(); + + /** + * Snapshot version for given account. + * + * @param snapshotVersion The snapshot version + * @return This builder. + */ + public Builder setSnapshotVersion(int snapshotVersion) { + mInstance.mSnapshotVersion = snapshotVersion; + return this; + } + + /** + * Sets the number of user secret guesses allowed during Keychain recovery. + * + * @param maxAttempts The maximum number of guesses. + * @return This builder. + */ + public Builder setMaxAttempts(int maxAttempts) { + mInstance.mMaxAttempts = maxAttempts; + return this; + } + + /** + * Sets counter id. + * + * @param counterId The counter id. + * @return This builder. + */ + public Builder setCounterId(long counterId) { + mInstance.mCounterId = counterId; + return this; + } + + /** + * Sets server parameters. + * + * @param serverParams The server parameters + * @return This builder. + */ + public Builder setServerParams(byte[] serverParams) { + mInstance.mServerParams = serverParams; + return this; + } + + /** + * Sets public key used to encrypt recovery blob. + * + * @param publicKey The public key + * @return This builder. + */ + public Builder setTrustedHardwarePublicKey(byte[] publicKey) { + mInstance.mPublicKey = publicKey; + return this; + } + + /** + * Sets UI and key derivation parameters + * + * @param recoveryMetadata The UI and key derivation parameters + * @return This builder. + */ + public Builder setKeychainProtectionParams( + @NonNull List<KeychainProtectionParams> recoveryMetadata) { + mInstance.mKeychainProtectionParams = recoveryMetadata; + return this; + } + + /** + * List of application keys. + * + * @param entryRecoveryData List of application keys + * @return This builder. + */ + public Builder setWrappedApplicationKeys(List<WrappedApplicationKey> entryRecoveryData) { + mInstance.mEntryRecoveryData = entryRecoveryData; + return this; + } + + /** + * Sets recovery key blob + * + * @param encryptedRecoveryKeyBlob The recovery key blob. + * @return This builder. + */ + public Builder setEncryptedRecoveryKeyBlob(@NonNull byte[] encryptedRecoveryKeyBlob) { + mInstance.mEncryptedRecoveryKeyBlob = encryptedRecoveryKeyBlob; + return this; + } + + + /** + * Creates a new {@link KeychainSnapshot} instance. + * + * @return new instance + * @throws NullPointerException if some required fields were not set. + */ + @NonNull public KeychainSnapshot build() { + Preconditions.checkCollectionElementsNotNull(mInstance.mKeychainProtectionParams, + "recoveryMetadata"); + Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData, + "entryRecoveryData"); + Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob); + Preconditions.checkNotNull(mInstance.mServerParams); + Preconditions.checkNotNull(mInstance.mPublicKey); + return mInstance; + } + } + + /** + * @hide + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mSnapshotVersion); + out.writeTypedList(mKeychainProtectionParams); + out.writeByteArray(mEncryptedRecoveryKeyBlob); + out.writeTypedList(mEntryRecoveryData); + out.writeInt(mMaxAttempts); + out.writeLong(mCounterId); + out.writeByteArray(mServerParams); + out.writeByteArray(mPublicKey); + } + + /** + * @hide + */ + protected KeychainSnapshot(Parcel in) { + mSnapshotVersion = in.readInt(); + mKeychainProtectionParams = in.createTypedArrayList(KeychainProtectionParams.CREATOR); + mEncryptedRecoveryKeyBlob = in.createByteArray(); + mEntryRecoveryData = in.createTypedArrayList(WrappedApplicationKey.CREATOR); + mMaxAttempts = in.readInt(); + mCounterId = in.readLong(); + mServerParams = in.createByteArray(); + mPublicKey = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/security/keystore/recovery/LockScreenRequiredException.java b/core/java/android/security/keystore/recovery/LockScreenRequiredException.java new file mode 100644 index 000000000000..ced23685690e --- /dev/null +++ b/core/java/android/security/keystore/recovery/LockScreenRequiredException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * Error thrown when trying to generate keys for a profile that has no lock screen set. + * + * <p>A lock screen must be set, as the lock screen is used to encrypt the snapshot. + * + * @hide + */ +public class LockScreenRequiredException extends RecoveryControllerException { + public LockScreenRequiredException(String msg) { + super(msg); + } +} diff --git a/core/java/android/security/keystore/recovery/RecoveryClaim.java b/core/java/android/security/keystore/recovery/RecoveryClaim.java new file mode 100644 index 000000000000..11385d883a77 --- /dev/null +++ b/core/java/android/security/keystore/recovery/RecoveryClaim.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * An attempt to recover a keychain protected by remote secure hardware. + * + * @hide + */ +public class RecoveryClaim { + + private final RecoverySession mRecoverySession; + private final byte[] mClaimBytes; + + RecoveryClaim(RecoverySession recoverySession, byte[] claimBytes) { + mRecoverySession = recoverySession; + mClaimBytes = claimBytes; + } + + /** + * Returns the session associated with the recovery attempt. This is used to match the symmetric + * key, which remains internal to the framework, for decrypting the claim response. + * + * @return The session data. + */ + public RecoverySession getRecoverySession() { + return mRecoverySession; + } + + /** + * Returns the encrypted claim's bytes. + * + * <p>This should be sent by the recovery agent to the remote secure hardware, which will use + * it to decrypt the keychain, before sending it re-encrypted with the session's symmetric key + * to the device. + */ + public byte[] getClaimBytes() { + return mClaimBytes; + } +} diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java new file mode 100644 index 000000000000..1908ce22bac2 --- /dev/null +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.PendingIntent; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.util.Log; + +import com.android.internal.widget.ILockSettings; + +import java.util.List; +import java.util.Map; + +/** + * An assistant for generating {@link javax.crypto.SecretKey} instances that can be recovered by + * other Android devices belonging to the user. The exported keychain is protected by the user's + * lock screen. + * + * <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible + * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force + * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10). + * After that number of incorrect guesses, the trusted hardware no longer allows access to the + * key chain. + * + * <p>For now only the recovery agent itself is able to create keys, so it is expected that the + * recovery agent is itself the system app. + * + * <p>A recovery agent requires the privileged permission + * {@code android.Manifest.permission#RECOVER_KEYSTORE}. + * + * @hide + */ +public class RecoveryController { + private static final String TAG = "RecoveryController"; + + /** Key has been successfully synced. */ + public static final int RECOVERY_STATUS_SYNCED = 0; + /** Waiting for recovery agent to sync the key. */ + public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; + /** Recovery account is not available. */ + public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2; + /** Key cannot be synced. */ + public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; + + /** + * Failed because no snapshot is yet pending to be synced for the user. + * + * @hide + */ + public static final int ERROR_NO_SNAPSHOT_PENDING = 21; + + /** + * Failed due to an error internal to the recovery service. This is unexpected and indicates + * either a problem with the logic in the service, or a problem with a dependency of the + * service (such as AndroidKeyStore). + * + * @hide + */ + public static final int ERROR_SERVICE_INTERNAL_ERROR = 22; + + /** + * Failed because the user does not have a lock screen set. + * + * @hide + */ + public static final int ERROR_INSECURE_USER = 23; + + /** + * Error thrown when attempting to use a recovery session that has since been closed. + * + * @hide + */ + public static final int ERROR_SESSION_EXPIRED = 24; + + /** + * Failed because the provided certificate was not a valid X509 certificate. + * + * @hide + */ + public static final int ERROR_BAD_CERTIFICATE_FORMAT = 25; + + /** + * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, + * the data has become corrupted, the data has been tampered with, etc. + * + * @hide + */ + public static final int ERROR_DECRYPTION_FAILED = 26; + + + private final ILockSettings mBinder; + + private RecoveryController(ILockSettings binder) { + mBinder = binder; + } + + /** + * Gets a new instance of the class. + */ + public static RecoveryController getInstance() { + ILockSettings lockSettings = + ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings")); + return new RecoveryController(lockSettings); + } + + /** + * Initializes key recovery service for the calling application. RecoveryController + * randomly chooses one of the keys from the list and keeps it to use for future key export + * operations. Collection of all keys in the list must be signed by the provided {@code + * rootCertificateAlias}, which must also be present in the list of root certificates + * preinstalled on the device. The random selection allows RecoveryController to select + * which of a set of remote recovery service devices will be used. + * + * <p>In addition, RecoveryController enforces a delay of three months between + * consecutive initialization attempts, to limit the ability of an attacker to often switch + * remote recovery devices and significantly increase number of recovery attempts. + * + * @param rootCertificateAlias alias of a root certificate preinstalled on the device + * @param signedPublicKeyList binary blob a list of X509 certificates and signature + * @throws BadCertificateFormatException if the {@code signedPublicKeyList} is in a bad format. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void initRecoveryService( + @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList) + throws BadCertificateFormatException, InternalRecoveryServiceException { + try { + mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) { + throw new BadCertificateFormatException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Returns data necessary to store all recoverable keys for given account. Key material is + * encrypted with user secret and recovery public key. + * + * @param account specific to Recovery agent. + * @return Data necessary to recover keystore. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + @NonNull public KeychainSnapshot getRecoveryData(@NonNull byte[] account) + throws InternalRecoveryServiceException { + try { + return mBinder.getRecoveryData(account); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_NO_SNAPSHOT_PENDING) { + return null; + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link + * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at + * most one registered listener at any time. + * + * @param intent triggered when new snapshot is available. Unregisters listener if the value is + * {@code null}. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent) + throws InternalRecoveryServiceException { + try { + mBinder.setSnapshotCreatedPendingIntent(intent); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot + * version. Version zero is used, if no snapshots were created for the account. + * + * @return Map from recovery agent accounts to snapshot versions. + * @see KeychainSnapshot#getSnapshotVersion + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions() + throws InternalRecoveryServiceException { + try { + // IPC doesn't support generic Maps. + @SuppressWarnings("unchecked") + Map<byte[], Integer> result = + (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions(); + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Server parameters used to generate new recovery key blobs. This value will be included in + * {@code KeychainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included + * in vaultParams {@link #startRecoverySession} + * + * @param serverParams included in recovery key blob. + * @see #getRecoveryData + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void setServerParams(byte[] serverParams) throws InternalRecoveryServiceException { + try { + mBinder.setServerParams(serverParams); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Updates recovery status for given keys. It is used to notify keystore that key was + * successfully stored on the server or there were an error. Application can check this value + * using {@code getRecoveyStatus}. + * + * @param packageName Application whose recoverable keys' statuses are to be updated. + * @param aliases List of application-specific key aliases. If the array is empty, updates the + * status for all existing recoverable keys. + * @param status Status specific to recovery agent. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void setRecoveryStatus( + @NonNull String packageName, @Nullable String[] aliases, int status) + throws NameNotFoundException, InternalRecoveryServiceException { + try { + mBinder.setRecoveryStatus(packageName, aliases, status); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status. + * Negative status values are reserved for recovery agent specific codes. List of common codes: + * + * <ul> + * <li>{@link #RECOVERY_STATUS_SYNCED} + * <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} + * <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT} + * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} + * </ul> + * + * @return {@code Map} from KeyStore alias to recovery status. + * @see #setRecoveryStatus + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public Map<String, Integer> getRecoveryStatus() throws InternalRecoveryServiceException { + try { + // IPC doesn't support generic Maps. + @SuppressWarnings("unchecked") + Map<String, Integer> result = + (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null); + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them + * is necessary to recover data. + * + * @param secretTypes {@link KeychainProtectionParams#TYPE_LOCKSCREEN} or {@link + * KeychainProtectionParams#TYPE_CUSTOM_PASSWORD} + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void setRecoverySecretTypes( + @NonNull @KeychainProtectionParams.UserSecretType int[] secretTypes) + throws InternalRecoveryServiceException { + try { + mBinder.setRecoverySecretTypes(secretTypes); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is + * necessary to generate KeychainSnapshot. + * + * @return list of recovery secret types + * @see KeychainSnapshot + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public @NonNull @KeychainProtectionParams.UserSecretType int[] getRecoverySecretTypes() + throws InternalRecoveryServiceException { + try { + return mBinder.getRecoverySecretTypes(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Returns a list of recovery secret types, necessary to create a pending recovery snapshot. + * When user enters a secret of a pending type {@link #recoverySecretAvailable} should be + * called. + * + * @return list of recovery secret types + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + @NonNull + public @KeychainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes() + throws InternalRecoveryServiceException { + try { + return mBinder.getPendingRecoverySecretTypes(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Method notifies KeyStore that a user-generated secret is available. This method generates a + * symmetric session key which a trusted remote device can use to return a recovery key. Caller + * should use {@link KeychainProtectionParams#clearSecret} to override the secret value in + * memory. + * + * @param recoverySecret user generated secret together with parameters necessary to regenerate + * it on a new device. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void recoverySecretAvailable(@NonNull KeychainProtectionParams recoverySecret) + throws InternalRecoveryServiceException { + try { + mBinder.recoverySecretAvailable(recoverySecret); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Initializes recovery session and returns a blob with proof of recovery secrets possession. + * The method generates symmetric key for a session, which trusted remote device can use to + * return recovery key. + * + * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key + * used to create the recovery blob on the source device. + * Keystore will verify the certificate using root of trust. + * @param vaultParams Must match the parameters in the corresponding field in the recovery blob. + * Used to limit number of guesses. + * @param vaultChallenge Data passed from server for this recovery session and used to prevent + * replay attacks + * @param secrets Secrets provided by user, the method only uses type and secret fields. + * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is + * encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric + * key and parameters necessary to identify the counter with the number of failed recovery + * attempts. + * @throws BadCertificateFormatException if the {@code verifierPublicKey} is in an incorrect + * format. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + @NonNull public RecoveryClaim startRecoverySession( + @NonNull byte[] verifierPublicKey, + @NonNull byte[] vaultParams, + @NonNull byte[] vaultChallenge, + @NonNull List<KeychainProtectionParams> secrets) + throws BadCertificateFormatException, InternalRecoveryServiceException { + try { + RecoverySession recoverySession = RecoverySession.newInstance(this); + byte[] recoveryClaim = + mBinder.startRecoverySession( + recoverySession.getSessionId(), + verifierPublicKey, + vaultParams, + vaultChallenge, + secrets); + return new RecoveryClaim(recoverySession, recoveryClaim); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) { + throw new BadCertificateFormatException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Imports keys. + * + * @param session Related recovery session, as originally created by invoking + * {@link #startRecoverySession(byte[], byte[], byte[], List)}. + * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session. + * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob + * and session. KeyStore only uses package names from the application info in {@link + * WrappedApplicationKey}. Caller is responsibility to perform certificates check. + * @return Map from alias to raw key material. + * @throws SessionExpiredException if {@code session} has since been closed. + * @throws DecryptionFailedException if unable to decrypt the snapshot. + * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service. + */ + public Map<String, byte[]> recoverKeys( + @NonNull RecoverySession session, + @NonNull byte[] recoveryKeyBlob, + @NonNull List<WrappedApplicationKey> applicationKeys) + throws SessionExpiredException, DecryptionFailedException, + InternalRecoveryServiceException { + try { + return (Map<String, byte[]>) mBinder.recoverKeys( + session.getSessionId(), recoveryKeyBlob, applicationKeys); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_DECRYPTION_FAILED) { + throw new DecryptionFailedException(e.getMessage()); + } + if (e.errorCode == ERROR_SESSION_EXPIRED) { + throw new SessionExpiredException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Deletes all data associated with {@code session}. Should not be invoked directly but via + * {@link RecoverySession#close()}. + * + * @hide + */ + void closeSession(RecoverySession session) { + try { + mBinder.closeSession(session.getSessionId()); + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Unexpected error trying to close session", e); + } + } + + /** + * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the + * raw material of the key. + * + * @param alias The key alias. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + * @throws LockScreenRequiredException if the user has not set a lock screen. This is required + * to generate recoverable keys, as the snapshots are encrypted using a key derived from the + * lock screen. + */ + public byte[] generateAndStoreKey(@NonNull String alias) + throws InternalRecoveryServiceException, LockScreenRequiredException { + try { + return mBinder.generateAndStoreKey(alias); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_INSECURE_USER) { + throw new LockScreenRequiredException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Removes a key called {@code alias} from the recoverable key store. + * + * @param alias The key alias. + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + */ + public void removeKey(@NonNull String alias) throws InternalRecoveryServiceException { + try { + mBinder.removeKey(alias); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw wrapUnexpectedServiceSpecificException(e); + } + } + + private InternalRecoveryServiceException wrapUnexpectedServiceSpecificException( + ServiceSpecificException e) { + if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) { + return new InternalRecoveryServiceException(e.getMessage()); + } + + // Should never happen. If it does, it's a bug, and we need to update how the method that + // called this throws its exceptions. + return new InternalRecoveryServiceException("Unexpected error code for method: " + + e.errorCode, e); + } +} diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/core/java/android/security/keystore/recovery/RecoveryControllerException.java new file mode 100644 index 000000000000..0fb7c07edd5b --- /dev/null +++ b/core/java/android/security/keystore/recovery/RecoveryControllerException.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import java.security.GeneralSecurityException; + +/** + * Base exception for errors thrown by {@link RecoveryController}. + * + * @hide + */ +public abstract class RecoveryControllerException extends GeneralSecurityException { + RecoveryControllerException() { } + + RecoveryControllerException(String msg) { + super(msg); + } + + public RecoveryControllerException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java new file mode 100644 index 000000000000..89f894529739 --- /dev/null +++ b/core/java/android/security/keystore/recovery/RecoverySession.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import java.security.SecureRandom; + +/** + * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a + * recovery agent. + * + * @hide + */ +public class RecoverySession implements AutoCloseable { + + private static final int SESSION_ID_LENGTH_BYTES = 16; + + private final String mSessionId; + private final RecoveryController mRecoveryController; + + private RecoverySession(RecoveryController recoveryController, String sessionId) { + mRecoveryController = recoveryController; + mSessionId = sessionId; + } + + /** + * A new session, started by {@code recoveryManager}. + */ + static RecoverySession newInstance(RecoveryController recoveryController) { + return new RecoverySession(recoveryController, newSessionId()); + } + + /** + * Returns a new random session ID. + */ + private static String newSessionId() { + SecureRandom secureRandom = new SecureRandom(); + byte[] sessionId = new byte[SESSION_ID_LENGTH_BYTES]; + secureRandom.nextBytes(sessionId); + StringBuilder sb = new StringBuilder(); + for (byte b : sessionId) { + sb.append(Byte.toHexString(b, /*upperCase=*/ false)); + } + return sb.toString(); + } + + /** + * An internal session ID, used by the framework to match recovery claims to snapshot responses. + */ + String getSessionId() { + return mSessionId; + } + + @Override + public void close() { + mRecoveryController.closeSession(this); + } +} diff --git a/core/java/android/security/keystore/recovery/SessionExpiredException.java b/core/java/android/security/keystore/recovery/SessionExpiredException.java new file mode 100644 index 000000000000..7fc2b0560d69 --- /dev/null +++ b/core/java/android/security/keystore/recovery/SessionExpiredException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +/** + * Error thrown when attempting to use a {@link RecoverySession} that has since expired. + * + * @hide + */ +public class SessionExpiredException extends RecoveryControllerException { + public SessionExpiredException(String msg) { + super(msg); + } +} diff --git a/core/java/android/security/keystore/WrappedApplicationKey.aidl b/core/java/android/security/keystore/recovery/WrappedApplicationKey.aidl index a6294fee03b3..b2d1ae461346 100644 --- a/core/java/android/security/keystore/WrappedApplicationKey.aidl +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.keystore; +package android.security.keystore.recovery; /* @hide */ parcelable WrappedApplicationKey; diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java new file mode 100644 index 000000000000..bca03b389e43 --- /dev/null +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore.recovery; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * Helper class with data necessary recover a single application key, given a recovery key. + * + * <ul> + * <li>Alias - Keystore alias of the key. + * <li>Encrypted key material. + * </ul> + * + * Note that Application info is not included. Recovery Agent can only make its own keys + * recoverable. + * + * @hide + */ +public final class WrappedApplicationKey implements Parcelable { + private String mAlias; + // The only supported format is AES-256 symmetric key. + private byte[] mEncryptedKeyMaterial; + + /** + * Builder for creating {@link WrappedApplicationKey}. + */ + public static class Builder { + private WrappedApplicationKey + mInstance = new WrappedApplicationKey(); + + /** + * Sets Application-specific alias of the key. + * + * @param alias The alias. + * @return This builder. + */ + public Builder setAlias(@NonNull String alias) { + mInstance.mAlias = alias; + return this; + } + + /** + * Sets key material encrypted by recovery key. + * + * @param encryptedKeyMaterial The key material + * @return This builder + */ + + public Builder setEncryptedKeyMaterial(@NonNull byte[] encryptedKeyMaterial) { + mInstance.mEncryptedKeyMaterial = encryptedKeyMaterial; + return this; + } + + /** + * Creates a new {@link WrappedApplicationKey} instance. + * + * @return new instance + * @throws NullPointerException if some required fields were not set. + */ + @NonNull public WrappedApplicationKey build() { + Preconditions.checkNotNull(mInstance.mAlias); + Preconditions.checkNotNull(mInstance.mEncryptedKeyMaterial); + return mInstance; + } + } + + private WrappedApplicationKey() { + + } + + /** + * Deprecated - consider using Builder. + * @hide + */ + public WrappedApplicationKey(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) { + mAlias = Preconditions.checkNotNull(alias); + mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial); + } + + /** + * Application-specific alias of the key. + * + * @see java.security.KeyStore.aliases + */ + public @NonNull String getAlias() { + return mAlias; + } + + /** Key material encrypted by recovery key. */ + public @NonNull byte[] getEncryptedKeyMaterial() { + return mEncryptedKeyMaterial; + } + + public static final Creator<WrappedApplicationKey> CREATOR = + new Creator<WrappedApplicationKey>() { + public WrappedApplicationKey createFromParcel(Parcel in) { + return new WrappedApplicationKey(in); + } + + public WrappedApplicationKey[] newArray(int length) { + return new WrappedApplicationKey[length]; + } + }; + + /** + * @hide + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(mAlias); + out.writeByteArray(mEncryptedKeyMaterial); + } + + /** + * @hide + */ + protected WrappedApplicationKey(Parcel in) { + mAlias = in.readString(); + mEncryptedKeyMaterial = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index a2a76169c83a..87943725ba21 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -80,10 +80,22 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV3Verifier.verify(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); - return new PackageParser.SigningDetails(signerSigs, - SignatureSchemeVersion.SIGNING_BLOCK_V3); + Signature[] pastSignerSigs = null; + int[] pastSignerSigsFlags = null; + if (vSigner.por != null) { + // populate proof-of-rotation information + pastSignerSigs = new Signature[vSigner.por.certs.size()]; + pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; + for (int i = 0; i < pastSignerSigs.length; i++) { + pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); + pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); + } + } + return new PackageParser.SigningDetails( + signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, + pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { - // not signed with v2, try older if allowed + // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); @@ -92,7 +104,7 @@ public class ApkSignatureVerifier { // APK Signature Scheme v2 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath - + " using APK Signature Scheme v2", e); + + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -304,25 +316,37 @@ public class ApkSignatureVerifier { } // first try v3 - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3"); + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV3"); try { ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); - return new PackageParser.SigningDetails(signerSigs, - SignatureSchemeVersion.SIGNING_BLOCK_V3); + Signature[] pastSignerSigs = null; + int[] pastSignerSigsFlags = null; + if (vSigner.por != null) { + // populate proof-of-rotation information + pastSignerSigs = new Signature[vSigner.por.certs.size()]; + pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; + for (int i = 0; i < pastSignerSigs.length; i++) { + pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); + pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); + } + } + return new PackageParser.SigningDetails( + signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, + pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { - // not signed with v2, try older if allowed + // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); } } catch (Exception e) { - // APK Signature Scheme v2 signature found but did not verify + // APK Signature Scheme v3 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath - + " using APK Signature Scheme v2", e); + + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 176927fef0eb..95abea14b1dd 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -2244,9 +2244,36 @@ public abstract class Window { * <p> * The transitionName for the view background will be "android:navigation:background". * </p> + * @attr ref android.R.styleable#Window_navigationBarColor */ public abstract void setNavigationBarColor(@ColorInt int color); + /** + * Shows a thin line of the specified color between the navigation bar and the app + * content. + * <p> + * For this to take effect, + * the window must be drawing the system bar backgrounds with + * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and + * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION} must not be set. + * + * @param dividerColor The color of the thin line. + * @attr ref android.R.styleable#Window_navigationBarDividerColor + */ + public void setNavigationBarDividerColor(@ColorInt int dividerColor) { + } + + /** + * Retrieves the color of the navigation bar divider. + * + * @return The color of the navigation bar divider color. + * @see #setNavigationBarColor(int) + * @attr ref android.R.styleable#Window_navigationBarDividerColor + */ + public @ColorInt int getNavigationBarDividerColor() { + return 0; + } + /** @hide */ public void setTheme(int resId) { } diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index f5c36139df0f..990fbdb019d6 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -156,6 +156,8 @@ public class AnimationUtils { anim = new RotateAnimation(c, attrs); } else if (name.equals("translate")) { anim = new TranslateAnimation(c, attrs); + } else if (name.equals("cliprect")) { + anim = new ClipRectAnimation(c, attrs); } else { throw new RuntimeException("Unknown animation name: " + parser.getName()); } diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java index e194927e8301..21509d3a1159 100644 --- a/core/java/android/view/animation/ClipRectAnimation.java +++ b/core/java/android/view/animation/ClipRectAnimation.java @@ -16,7 +16,11 @@ package android.view.animation; +import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.DisplayMetrics; /** * An animation that controls the clip of an object. See the @@ -26,8 +30,84 @@ import android.graphics.Rect; * @hide */ public class ClipRectAnimation extends Animation { - protected Rect mFromRect = new Rect(); - protected Rect mToRect = new Rect(); + protected final Rect mFromRect = new Rect(); + protected final Rect mToRect = new Rect(); + + private int mFromLeftType = ABSOLUTE; + private int mFromTopType = ABSOLUTE; + private int mFromRightType = ABSOLUTE; + private int mFromBottomType = ABSOLUTE; + + private int mToLeftType = ABSOLUTE; + private int mToTopType = ABSOLUTE; + private int mToRightType = ABSOLUTE; + private int mToBottomType = ABSOLUTE; + + private float mFromLeftValue; + private float mFromTopValue; + private float mFromRightValue; + private float mFromBottomValue; + + private float mToLeftValue; + private float mToTopValue; + private float mToRightValue; + private float mToBottomValue; + + /** + * Constructor used when a ClipRectAnimation is loaded from a resource. + * + * @param context Application context to use + * @param attrs Attribute set from which to read values + */ + public ClipRectAnimation(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.ClipRectAnimation); + + Description d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_fromLeft)); + mFromLeftType = d.type; + mFromLeftValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_fromTop)); + mFromTopType = d.type; + mFromTopValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_fromRight)); + mFromRightType = d.type; + mFromRightValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_fromBottom)); + mFromBottomType = d.type; + mFromBottomValue = d.value; + + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_toLeft)); + mToLeftType = d.type; + mToLeftValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_toTop)); + mToTopType = d.type; + mToTopValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_toRight)); + mToRightType = d.type; + mToRightValue = d.value; + + d = Description.parseValue(a.peekValue( + com.android.internal.R.styleable.ClipRectAnimation_toBottom)); + mToBottomType = d.type; + mToBottomValue = d.value; + + a.recycle(); + } /** * Constructor to use when building a ClipRectAnimation from code @@ -39,8 +119,15 @@ public class ClipRectAnimation extends Animation { if (fromClip == null || toClip == null) { throw new RuntimeException("Expected non-null animation clip rects"); } - mFromRect.set(fromClip); - mToRect.set(toClip); + mFromLeftValue = fromClip.left; + mFromTopValue = fromClip.top; + mFromRightValue= fromClip.right; + mFromBottomValue = fromClip.bottom; + + mToLeftValue = toClip.left; + mToTopValue = toClip.top; + mToRightValue= toClip.right; + mToBottomValue = toClip.bottom; } /** @@ -48,8 +135,7 @@ public class ClipRectAnimation extends Animation { */ public ClipRectAnimation(int fromL, int fromT, int fromR, int fromB, int toL, int toT, int toR, int toB) { - mFromRect.set(fromL, fromT, fromR, fromB); - mToRect.set(toL, toT, toR, toB); + this(new Rect(fromL, fromT, fromR, fromB), new Rect(toL, toT, toR, toB)); } @Override @@ -65,4 +151,17 @@ public class ClipRectAnimation extends Animation { public boolean willChangeTransformationMatrix() { return false; } + + @Override + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + mFromRect.set((int) resolveSize(mFromLeftType, mFromLeftValue, width, parentWidth), + (int) resolveSize(mFromTopType, mFromTopValue, height, parentHeight), + (int) resolveSize(mFromRightType, mFromRightValue, width, parentWidth), + (int) resolveSize(mFromBottomType, mFromBottomValue, height, parentHeight)); + mToRect.set((int) resolveSize(mToLeftType, mToLeftValue, width, parentWidth), + (int) resolveSize(mToTopType, mToTopValue, height, parentHeight), + (int) resolveSize(mToRightType, mToRightValue, width, parentWidth), + (int) resolveSize(mToBottomType, mToBottomValue, height, parentHeight)); + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index b1c45f729fcb..039b66d4cd7d 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6947,6 +6947,8 @@ public class BatteryStatsImpl extends BatteryStats { WIFI_MULTICAST_ENABLED, mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase); } mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs); + StatsLog.write_non_chained( + StatsLog.WIFI_MULTICAST_LOCK_STATE_CHANGED, getUid(), null, 1); } } @@ -6955,6 +6957,8 @@ public class BatteryStatsImpl extends BatteryStats { if (mWifiMulticastEnabled) { mWifiMulticastEnabled = false; mWifiMulticastTimer.stopRunningLocked(elapsedRealtimeMs); + StatsLog.write_non_chained( + StatsLog.WIFI_MULTICAST_LOCK_STATE_CHANGED, getUid(), null, 0); } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index e8ee29dc19f8..34b5ec8149a7 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -3810,6 +3810,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + public void setNavigationBarDividerColor(int navigationBarDividerColor) { + mNavigationBarDividerColor = navigationBarDividerColor; + if (mDecor != null) { + mDecor.updateColorViews(null, false /* animate */); + } + } + + @Override + public int getNavigationBarDividerColor() { + return mNavigationBarDividerColor; + } + public void setIsStartingWindow(boolean isStartingWindow) { mIsStartingWindow = isStartingWindow; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index e3f1f472ce5e..f9da1eb26669 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -19,9 +19,9 @@ package com.android.internal.widget; import android.app.PendingIntent; import android.app.trust.IStrongAuthTracker; import android.os.Bundle; -import android.security.keystore.WrappedApplicationKey; -import android.security.keystore.KeychainSnapshot; -import android.security.keystore.KeychainProtectionParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.security.keystore.recovery.KeychainSnapshot; +import android.security.keystore.recovery.KeychainProtectionParams; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.VerifyCredentialResponse; diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp index 34544d37a6bf..daa20876ba65 100644 --- a/core/jni/android_database_SQLiteCommon.cpp +++ b/core/jni/android_database_SQLiteCommon.cpp @@ -223,8 +223,8 @@ void throw_sqlite3_exception(JNIEnv* env, int errcode, if (sqlite3Message) { String8 fullMessage; fullMessage.append(sqlite3Message); - const char* errcode_msg = sqlite3_error_code_to_msg(errcode).c_str(); - fullMessage.appendFormat(" (code %s)", errcode_msg); // print extended error code + std::string errcode_msg = sqlite3_error_code_to_msg(errcode); + fullMessage.appendFormat(" (code %s)", errcode_msg.c_str()); // print extended error code if (message) { fullMessage.append(": "); fullMessage.append(message); diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml index a67b0ca38519..371bcfef7ec9 100644 --- a/core/res/res/anim/activity_close_enter.xml +++ b/core/res/res/anim/activity_close_enter.xml @@ -17,9 +17,17 @@ */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal"> - <alpha android:fromAlpha="0.7" android:toAlpha="1.0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/linear_out_slow_in" - android:duration="250"/> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + <translate + android:fromYDelta="-2%" + android:toYDelta="0" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="425"/> + <alpha + android:fromAlpha="0.9" + android:toAlpha="1.0" + android:interpolator="@interpolator/activity_close_dim" + android:startOffset="0" + android:duration="425"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml index d8c42ed808f1..143bedb985e1 100644 --- a/core/res/res/anim/activity_close_exit.xml +++ b/core/res/res/anim/activity_close_exit.xml @@ -18,15 +18,27 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> - <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:interpolator="@interpolator/linear" - android:fillEnabled="true" - android:fillBefore="false" android:fillAfter="true" - android:startOffset="100" - android:duration="150"/> - <translate android:fromYDelta="0%" android:toYDelta="8%" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_quart" - android:duration="250"/> + android:shareInterpolator="false" + android:zAdjustment="top"> + <translate + android:fromYDelta="0" + android:toYDelta="4.1%" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="425"/> + <cliprect + android:fromLeft="0%" + android:fromTop="0%" + android:fromRight="100%" + android:fromBottom="100%" + android:toLeft="0%" + android:toTop="95.9%" + android:toRight="100%" + android:toBottom="100%" + android:interpolator="@interpolator/exaggerated_ease" + android:duration="425"/> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1.0" + android:interpolator="@interpolator/fast_out_linear_in" + android:duration="425"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml index 1d949d2f7446..f9381b458c20 100644 --- a/core/res/res/anim/activity_open_enter.xml +++ b/core/res/res/anim/activity_open_enter.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -18,15 +17,21 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="top"> - <alpha android:fromAlpha="0.0" android:toAlpha="1.0" - android:interpolator="@interpolator/decelerate_quart" - android:fillEnabled="true" - android:fillBefore="false" android:fillAfter="true" - android:duration="200"/> - <translate android:fromYDelta="8%" android:toYDelta="0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_quint" - android:duration="350"/> + android:shareInterpolator="false"> + <translate + android:fromYDelta="4.1%" + android:toYDelta="0" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="425"/> + <cliprect + android:fromLeft="0%" + android:fromTop="95.9%" + android:fromRight="100%" + android:fromBottom="100%" + android:toLeft="0%" + android:toTop="0%" + android:toRight="100%" + android:toBottom="100%" + android:interpolator="@interpolator/exaggerated_ease" + android:duration="425"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml index 3a84197f8f63..d52b150391fb 100644 --- a/core/res/res/anim/activity_open_exit.xml +++ b/core/res/res/anim/activity_open_exit.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -18,9 +17,15 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:background="#ff000000" android:zAdjustment="normal"> - <alpha android:fromAlpha="1.0" android:toAlpha="0.7" - android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="217"/> + android:shareInterpolator="false"> + <translate + android:fromYDelta="0" + android:toYDelta="-2%" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="425"/> + <alpha + android:fromAlpha="1.0" + android:toAlpha="0.9" + android:interpolator="@interpolator/linear" + android:duration="117"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml index bea0ee51d593..81d1300038e3 100644 --- a/core/res/res/anim/task_close_enter.xml +++ b/core/res/res/anim/task_close_enter.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -16,27 +15,54 @@ ** limitations under the License. */ --> - <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="normal"> + android:shareInterpolator="false" + android:zAdjustment="top"> + + <alpha + android:fromAlpha="1" + android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="67" + android:duration="217"/> - <alpha android:fromAlpha="0.6" android:toAlpha="1.0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_cubic" - android:startOffset="600" - android:duration="133"/> + <translate + android:fromXDelta="105%" + android:toXDelta="0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/aggressive_ease" + android:startOffset="50" + android:duration="383"/> - <translate android:fromYDelta="10%" android:toYDelta="0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_cubic" - android:startOffset="300" - android:duration="433" /> + <scale + android:fromXScale="1.0526" + android:toXScale="1" + android:fromYScale="1.0526" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="283"/> - <scale android:fromXScale=".9" android:toXScale="1.0" - android:fromYScale=".9" android:toYScale="1.0" - android:pivotX="50%p" android:pivotY="0%p" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/fast_out_slow_in" - android:startOffset="300" - android:duration="433" /> + <scale + android:fromXScale="0.95" + android:toXScale="1" + android:fromYScale="0.95" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:startOffset="283" + android:duration="317"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index b6a08070c3ce..ab8b89ce7b06 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -18,20 +17,44 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> + android:shareInterpolator="false"> - <alpha android:fromAlpha="1.0" android:toAlpha="0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_quad" - android:startOffset="250" - android:duration="167"/> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="67" + android:duration="283"/> - <translate android:fromYDelta="0" android:toYDelta="110%" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_quint" - android:duration="417"/> + <translate + android:fromXDelta="0" + android:toXDelta="-105%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/aggressive_ease" + android:startOffset="50" + android:duration="383"/> + + <scale + android:fromXScale="1.0" + android:toXScale="0.95" + android:fromYScale="1.0" + android:toYScale="0.95" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:pivotX="50%" + android:pivotY="50%" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="283"/> <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha android:fromAlpha="1.0" android:toAlpha="1.0" - android:duration="700" /> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1.0" + android:duration="600"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml index b73e14fc637f..2ee7cd86e323 100644 --- a/core/res/res/anim/task_open_enter.xml +++ b/core/res/res/anim/task_open_enter.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -15,20 +14,55 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ ---> -<!-- This should in sync with task_open_enter_cross_profile_apps.xml --> +--><!-- This should in sync with task_open_enter_cross_profile_apps.xml --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> + android:shareInterpolator="false" + android:zAdjustment="top"> - <alpha android:fromAlpha="0" android:toAlpha="1.0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_quart" - android:startOffset="300" - android:duration="167"/> + <alpha + android:fromAlpha="1" + android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="67" + android:duration="217"/> - <translate android:fromYDelta="110%" android:toYDelta="0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_quint" - android:startOffset="300" - android:duration="417" /> + <translate + android:fromXDelta="-105%" + android:toXDelta="0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/aggressive_ease" + android:startOffset="50" + android:duration="383"/> + + <scale + android:fromXScale="1.0526" + android:toXScale="1" + android:fromYScale="1.0526" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="283"/> + + <scale + android:fromXScale="0.95" + android:toXScale="1" + android:fromYScale="0.95" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:startOffset="283" + android:duration="317"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/task_open_enter_cross_profile_apps.xml b/core/res/res/anim/task_open_enter_cross_profile_apps.xml index ad89fde92065..a92425e89960 100644 --- a/core/res/res/anim/task_open_enter_cross_profile_apps.xml +++ b/core/res/res/anim/task_open_enter_cross_profile_apps.xml @@ -18,24 +18,61 @@ --> <!-- This should in sync with task_open_enter.xml --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" android:zAdjustment="top"> + android:shareInterpolator="false" + android:zAdjustment="top"> - <alpha android:fromAlpha="0" android:toAlpha="1.0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_quart" - android:startOffset="300" - android:duration="167"/> + <alpha + android:fromAlpha="1" + android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="67" + android:duration="217"/> - <translate android:fromYDelta="110%" android:toYDelta="0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/decelerate_quint" - android:startOffset="300" - android:duration="417"/> + <translate + android:fromXDelta="-105%" + android:toXDelta="0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/aggressive_ease" + android:startOffset="50" + android:duration="383"/> + + <scale + android:fromXScale="1.0526" + android:toXScale="1" + android:fromYScale="1.0526" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="283"/> + + <scale + android:fromXScale="0.95" + android:toXScale="1" + android:fromYScale="0.95" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_slow_in" + android:startOffset="283" + android:duration="317"/> <!-- To keep the transition around longer for the thumbnail, should be kept in sync with cross_profile_apps_thumbmail.xml --> - <alpha android:fromAlpha="1.0" android:toAlpha="1.0" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:startOffset="717" - android:duration="200"/> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1.0" + android:startOffset="717" + android:duration="200"/> </set>
\ No newline at end of file diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml index 78d0fb015ce3..ecb98ce2cb16 100644 --- a/core/res/res/anim/task_open_exit.xml +++ b/core/res/res/anim/task_open_exit.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- /* ** Copyright 2009, The Android Open Source Project ** @@ -18,26 +17,44 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" - android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal"> + android:shareInterpolator="false"> - <alpha android:fromAlpha="1.0" android:toAlpha="0.6" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_cubic" - android:duration="133"/> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="67" + android:duration="283"/> - <translate android:fromYDelta="0" android:toYDelta="10%" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_cubic" - android:duration="433"/> + <translate + android:fromXDelta="0" + android:toXDelta="105%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/aggressive_ease" + android:startOffset="50" + android:duration="383"/> - <scale android:fromXScale="1.0" android:toXScale="0.9" - android:fromYScale="1.0" android:toYScale="0.9" - android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:pivotX="50%p" android:pivotY="50%p" - android:interpolator="@interpolator/fast_out_slow_in" - android:duration="433" /> + <scale + android:fromXScale="1.0" + android:toXScale="0.95" + android:fromYScale="1.0" + android:toYScale="0.95" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:pivotX="50%" + android:pivotY="50%" + android:interpolator="@interpolator/fast_out_slow_in" + android:duration="283"/> <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha android:fromAlpha="1.0" android:toAlpha="1.0" - android:duration="700" /> + <alpha + android:fromAlpha="1.0" + android:toAlpha="1.0" + android:duration="600"/> </set>
\ No newline at end of file diff --git a/core/res/res/interpolator/activity_close_dim.xml b/core/res/res/interpolator/activity_close_dim.xml new file mode 100644 index 000000000000..faad1399ff49 --- /dev/null +++ b/core/res/res/interpolator/activity_close_dim.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.33" + android:controlY1="0" + android:controlX2="1" + android:controlY2="1"/> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 4eaf93d822b2..4d80b2f0c00b 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2066,7 +2066,8 @@ <p>For this to take effect, the window must be drawing the system bar backgrounds with {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not have been requested to be translucent with - {@link android.R.attr#windowTranslucentNavigation}. --> + {@link android.R.attr#windowTranslucentNavigation}. + Corresponds to {@link android.view.Window#setNavigationBarDividerColor(int)}. --> <attr name="navigationBarDividerColor" format="color" /> <!-- The duration, in milliseconds, of the window background fade duration @@ -6336,6 +6337,17 @@ <attr name="toAlpha" format="float" /> </declare-styleable> + <declare-styleable name="ClipRectAnimation"> + <attr name="fromLeft" format="fraction" /> + <attr name="fromTop" format="fraction" /> + <attr name="fromRight" format="fraction" /> + <attr name="fromBottom" format="fraction" /> + <attr name="toLeft" format="fraction" /> + <attr name="toTop" format="fraction" /> + <attr name="toRight" format="fraction" /> + <attr name="toBottom" format="fraction" /> + </declare-styleable> + <declare-styleable name="LayoutAnimation"> <!-- Fraction of the animation duration used to delay the beginning of the animation of each child. --> diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml index 2c4058acc972..35eee6a3b175 100644 --- a/core/res/res/values/locale_config.xml +++ b/core/res/res/values/locale_config.xml @@ -23,35 +23,60 @@ <item>ak-GH</item> <!-- Akan (Ghana) --> <item>am-ET</item> <!-- Amharic (Ethiopia) --> <item>ar-AE</item> <!-- Arabic (United Arab Emirates) --> + <item>ar-AE-u-nu-latn</item> <!-- Arabic (United Arab Emirates,Western Digits) --> <item>ar-BH</item> <!-- Arabic (Bahrain) --> + <item>ar-BH-u-nu-latn</item> <!-- Arabic (Bahrain,Western Digits) --> <item>ar-DJ</item> <!-- Arabic (Djibouti) --> + <item>ar-DJ-u-nu-latn</item> <!-- Arabic (Djibouti,Western Digits) --> <item>ar-DZ</item> <!-- Arabic (Algeria) --> + <item>ar-DZ-u-nu-arab</item> <!-- Arabic (Algeria,Arabic-Indic Digits) --> <item>ar-EG</item> <!-- Arabic (Egypt) --> <item>ar-EG-u-nu-latn</item> <!-- Arabic (Egypt,Western Digits) --> <item>ar-EH</item> <!-- Arabic (Western Sahara) --> + <item>ar-EH-u-nu-arab</item> <!-- Arabic (Western Sahara,Arabic-Indic Digits) --> <item>ar-ER</item> <!-- Arabic (Eritrea) --> + <item>ar-ER-u-nu-latn</item> <!-- Arabic (Eritrea,Western Digits) --> <item>ar-IL</item> <!-- Arabic (Israel) --> + <item>ar-IL-u-nu-latn</item> <!-- Arabic (Israel,Western Digits) --> <item>ar-IQ</item> <!-- Arabic (Iraq) --> + <item>ar-IQ-u-nu-latn</item> <!-- Arabic (Iraq,Western Digits) --> <item>ar-JO</item> <!-- Arabic (Jordan) --> + <item>ar-JO-u-nu-latn</item> <!-- Arabic (Jordan,Western Digits) --> <item>ar-KM</item> <!-- Arabic (Comoros) --> + <item>ar-KM-u-nu-latn</item> <!-- Arabic (Comoros,Western Digits) --> <item>ar-KW</item> <!-- Arabic (Kuwait) --> + <item>ar-KW-u-nu-latn</item> <!-- Arabic (Kuwait,Western Digits) --> <item>ar-LB</item> <!-- Arabic (Lebanon) --> + <item>ar-LB-u-nu-latn</item> <!-- Arabic (Lebanon,Western Digits) --> <item>ar-LY</item> <!-- Arabic (Libya) --> + <item>ar-LY-u-nu-arab</item> <!-- Arabic (Libya,Arabic-Indic Digits) --> <item>ar-MA</item> <!-- Arabic (Morocco) --> + <item>ar-MA-u-nu-arab</item> <!-- Arabic (Morocco,Arabic-Indic Digits) --> <item>ar-MR</item> <!-- Arabic (Mauritania) --> + <item>ar-MR-u-nu-latn</item> <!-- Arabic (Mauritania,Western Digits) --> <item>ar-OM</item> <!-- Arabic (Oman) --> + <item>ar-OM-u-nu-latn</item> <!-- Arabic (Oman,Western Digits) --> <item>ar-PS</item> <!-- Arabic (Palestine) --> + <item>ar-PS-u-nu-latn</item> <!-- Arabic (Palestine,Western Digits) --> <item>ar-QA</item> <!-- Arabic (Qatar) --> + <item>ar-QA-u-nu-latn</item> <!-- Arabic (Qatar,Western Digits) --> <item>ar-SA</item> <!-- Arabic (Saudi Arabia) --> + <item>ar-SA-u-nu-latn</item> <!-- Arabic (Saudi Arabia,Western Digits) --> <item>ar-SD</item> <!-- Arabic (Sudan) --> + <item>ar-SD-u-nu-latn</item> <!-- Arabic (Sudan,Western Digits) --> <item>ar-SO</item> <!-- Arabic (Somalia) --> + <item>ar-SO-u-nu-latn</item> <!-- Arabic (Somalia,Western Digits) --> <item>ar-SS</item> <!-- Arabic (South Sudan) --> + <item>ar-SS-u-nu-latn</item> <!-- Arabic (South Sudan,Western Digits) --> <item>ar-SY</item> <!-- Arabic (Syria) --> + <item>ar-SY-u-nu-latn</item> <!-- Arabic (Syria,Western Digits) --> <item>ar-TD</item> <!-- Arabic (Chad) --> + <item>ar-TD-u-nu-latn</item> <!-- Arabic (Chad,Western Digits) --> <item>ar-TN</item> <!-- Arabic (Tunisia) --> <item>ar-TN-u-nu-arab</item> <!-- Arabic (Tunisia,Arabic-Indic Digits) --> <item>ar-XB</item> <!-- Right-to-left pseudolocale --> <item>ar-YE</item> <!-- Arabic (Yemen) --> + <item>ar-YE-u-nu-latn</item> <!-- Arabic (Yemen,Western Digits) --> <item>as-IN</item> <!-- Assamese (India) --> <item>asa-TZ</item> <!-- Asu (Tanzania) --> <item>az-Cyrl-AZ</item> <!-- Azerbaijani (Cyrillic,Azerbaijan) --> @@ -63,7 +88,9 @@ <item>bg-BG</item> <!-- Bulgarian (Bulgaria) --> <item>bm-ML</item> <!-- Bambara (Mali) --> <item>bn-BD</item> <!-- Bengali (Bangladesh) --> + <item>bn-BD-u-nu-latn</item> <!-- Bengali (Bangladesh,Western Digits) --> <item>bn-IN</item> <!-- Bengali (India) --> + <item>bn-IN-u-nu-latn</item> <!-- Bengali (India,Western Digits) --> <item>bo-CN</item> <!-- Tibetan (China) --> <item>bo-IN</item> <!-- Tibetan (India) --> <item>br-FR</item> <!-- Breton (France) --> @@ -230,7 +257,9 @@ <item>eu-ES</item> <!-- Basque (Spain) --> <item>ewo-CM</item> <!-- Ewondo (Cameroon) --> <item>fa-AF</item> <!-- Persian (Afghanistan) --> + <item>fa-AF-u-nu-latn</item> <!-- Persian (Afghanistan,Western Digits) --> <item>fa-IR</item> <!-- Persian (Iran) --> + <item>fa-IR-u-nu-latn</item> <!-- Persian (Iran,Western Digits) --> <item>ff-CM</item> <!-- Fulah (Cameroon) --> <item>ff-GN</item> <!-- Fulah (Guinea) --> <item>ff-MR</item> <!-- Fulah (Mauritania) --> @@ -473,7 +502,9 @@ <item>ug-CN</item> <!-- Uyghur (China) --> <item>uk-UA</item> <!-- Ukrainian (Ukraine) --> <item>ur-IN</item> <!-- Urdu (India) --> + <item>ur-IN-u-nu-latn</item> <!-- Urdu (India,Western Digits) --> <item>ur-PK</item> <!-- Urdu (Pakistan) --> + <item>ur-PK-u-nu-arabext</item> <!-- Urdu (Pakistan,Extended Arabic-Indic Digits) --> <item>uz-Arab-AF</item> <!-- Uzbek (Arabic,Afghanistan) --> <item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic,Uzbekistan) --> <item>uz-Latn-UZ</item> <!-- Uzbek (Latin,Uzbekistan) --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 170ba4264e04..9cab9fa45014 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4480,7 +4480,7 @@ <string name="zen_mode_alarm">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g> (next alarm)</string> <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] --> - <string name="zen_mode_forever">Until you turn off Do Not Disturb</string> + <string name="zen_mode_forever">Until you turn off</string> <!-- Zen mode condition: no exit criteria, includes the name of the feature for emphasis. [CHAR LIMIT=NONE] --> <string name="zen_mode_forever_dnd">Until you turn off Do Not Disturb</string> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 4be6408dca16..09192f4fa72f 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -172,6 +172,8 @@ <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" /> <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" /> + <assign-permission name="android.permission.DUMP" uid="statsd" /> + <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" /> <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" /> <!-- This is a list of all the libraries available for application diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 1690e8ce9309..e25386baf969 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -510,6 +510,19 @@ public class KeyStore { return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); } + public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, + String wrappingKeyAlias, + byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, + KeyCharacteristics outCharacteristics) { + try { + return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + maskingKey, args, rootSid, fingerprintSid, outCharacteristics); + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return SYSTEM_ERROR; + } + } + public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid) { try { diff --git a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java new file mode 100644 index 000000000000..01fd0624572c --- /dev/null +++ b/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import android.security.keymaster.KeymasterArguments; +import android.security.keymaster.KeymasterDefs; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.Arrays; + +import javax.crypto.CipherSpi; +import javax.crypto.spec.IvParameterSpec; + +/** + * Base class for Android Keystore 3DES {@link CipherSpi} implementations. + * + * @hide + */ +public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase { + + private static final int BLOCK_SIZE_BYTES = 8; + + private final int mKeymasterBlockMode; + private final int mKeymasterPadding; + /** Whether this transformation requires an IV. */ + private final boolean mIvRequired; + + private byte[] mIv; + + /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ + private boolean mIvHasBeenUsed; + + AndroidKeyStore3DESCipherSpi( + int keymasterBlockMode, + int keymasterPadding, + boolean ivRequired) { + mKeymasterBlockMode = keymasterBlockMode; + mKeymasterPadding = keymasterPadding; + mIvRequired = ivRequired; + } + + abstract static class ECB extends AndroidKeyStore3DESCipherSpi { + protected ECB(int keymasterPadding) { + super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false); + } + + public static class NoPadding extends ECB { + public NoPadding() { + super(KeymasterDefs.KM_PAD_NONE); + } + } + + public static class PKCS7Padding extends ECB { + public PKCS7Padding() { + super(KeymasterDefs.KM_PAD_PKCS7); + } + } + } + + abstract static class CBC extends AndroidKeyStore3DESCipherSpi { + protected CBC(int keymasterPadding) { + super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true); + } + + public static class NoPadding extends CBC { + public NoPadding() { + super(KeymasterDefs.KM_PAD_NONE); + } + } + + public static class PKCS7Padding extends CBC { + public PKCS7Padding() { + super(KeymasterDefs.KM_PAD_PKCS7); + } + } + } + + @Override + protected void initKey(int i, Key key) throws InvalidKeyException { + if (!(key instanceof AndroidKeyStoreSecretKey)) { + throw new InvalidKeyException( + "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); + } + if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) { + throw new InvalidKeyException( + "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " + + KeyProperties.KEY_ALGORITHM_3DES + " supported"); + } + setKey((AndroidKeyStoreSecretKey) key); + } + + @Override + protected int engineGetBlockSize() { + return BLOCK_SIZE_BYTES; + } + + @Override + protected int engineGetOutputSize(int inputLen) { + return inputLen + 3 * BLOCK_SIZE_BYTES; + } + + @Override + protected final byte[] engineGetIV() { + return ArrayUtils.cloneIfNotEmpty(mIv); + } + + @Override + protected AlgorithmParameters engineGetParameters() { + if (!mIvRequired) { + return null; + } + if ((mIv != null) && (mIv.length > 0)) { + try { + AlgorithmParameters params = AlgorithmParameters.getInstance("DESede"); + params.init(new IvParameterSpec(mIv)); + return params; + } catch (NoSuchAlgorithmException e) { + throw new ProviderException( + "Failed to obtain 3DES AlgorithmParameters", e); + } catch (InvalidParameterSpecException e) { + throw new ProviderException( + "Failed to initialize 3DES AlgorithmParameters with an IV", + e); + } + } + return null; + } + + @Override + protected void initAlgorithmSpecificParameters() throws InvalidKeyException { + if (!mIvRequired) { + return; + } + + // IV is used + if (!isEncrypting()) { + throw new InvalidKeyException("IV required when decrypting" + + ". Use IvParameterSpec or AlgorithmParameters to provide it."); + } + } + + @Override + protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (!mIvRequired) { + if (params != null) { + throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); + } + return; + } + + // IV is used + if (params == null) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException( + "IvParameterSpec must be provided when decrypting"); + } + return; + } + if (!(params instanceof IvParameterSpec)) { + throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported"); + } + mIv = ((IvParameterSpec) params).getIV(); + if (mIv == null) { + throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec"); + } + } + + @Override + protected void initAlgorithmSpecificParameters(AlgorithmParameters params) + throws InvalidAlgorithmParameterException { + if (!mIvRequired) { + if (params != null) { + throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); + } + return; + } + + // IV is used + if (params == null) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException("IV required when decrypting" + + ". Use IvParameterSpec or AlgorithmParameters to provide it."); + } + return; + } + + if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) { + throw new InvalidAlgorithmParameterException( + "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm() + + ". Supported: DESede"); + } + + IvParameterSpec ivSpec; + try { + ivSpec = params.getParameterSpec(IvParameterSpec.class); + } catch (InvalidParameterSpecException e) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException("IV required when decrypting" + + ", but not found in parameters: " + params, e); + } + mIv = null; + return; + } + mIv = ivSpec.getIV(); + if (mIv == null) { + throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters"); + } + } + + @Override + protected final int getAdditionalEntropyAmountForBegin() { + if ((mIvRequired) && (mIv == null) && (isEncrypting())) { + // IV will need to be generated + return BLOCK_SIZE_BYTES; + } + + return 0; + } + + @Override + protected int getAdditionalEntropyAmountForFinish() { + return 0; + } + + @Override + protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) { + if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) { + // IV is being reused for encryption: this violates security best practices. + throw new IllegalStateException( + "IV has already been used. Reusing IV in encryption mode violates security best" + + " practices."); + } + + keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES); + keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode); + keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); + if ((mIvRequired) && (mIv != null)) { + keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv); + } + } + + @Override + protected void loadAlgorithmSpecificParametersFromBeginResult( + KeymasterArguments keymasterArgs) { + mIvHasBeenUsed = true; + + // NOTE: Keymaster doesn't always return an IV, even if it's used. + byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null); + if ((returnedIv != null) && (returnedIv.length == 0)) { + returnedIv = null; + } + + if (mIvRequired) { + if (mIv == null) { + mIv = returnedIv; + } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { + throw new ProviderException("IV in use differs from provided IV"); + } + } else { + if (returnedIv != null) { + throw new ProviderException( + "IV in use despite IV not being used by this transformation"); + } + } + } + + @Override + protected final void resetAll() { + mIv = null; + mIvHasBeenUsed = false; + super.resetAll(); + } +} diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java index be390ffca2d9..e4cf84afcb8f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java @@ -93,6 +93,16 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSymmetricCipherImpl("AES/CTR/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding"); + putSymmetricCipherImpl("DESede/CBC/NoPadding", + PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding"); + putSymmetricCipherImpl("DESede/CBC/PKCS7Padding", + PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding"); + + putSymmetricCipherImpl("DESede/ECB/NoPadding", + PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding"); + putSymmetricCipherImpl("DESede/ECB/PKCS7Padding", + PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding"); + putSymmetricCipherImpl("AES/GCM/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding"); diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java index fdebf3793f12..5bcb34a67a54 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java @@ -307,7 +307,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor * * <p>This implementation returns {@code null}. * - * @returns stream or {@code null} if AAD is not supported by this cipher. + * @return stream or {@code null} if AAD is not supported by this cipher. */ @Nullable protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java index f1d1e1665387..379e17701c8f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -60,6 +60,12 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } } + public static class DESede extends AndroidKeyStoreKeyGeneratorSpi { + public DESede() { + super(KeymasterDefs.KM_ALGORITHM_3DES, 168); + } + } + protected static abstract class HmacBase extends AndroidKeyStoreKeyGeneratorSpi { protected HmacBase(int keymasterDigest) { super(KeymasterDefs.KM_ALGORITHM_HMAC, diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java index 55e6519d805d..10189263e98f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java @@ -80,6 +80,7 @@ public class AndroidKeyStoreProvider extends Provider { // javax.crypto.KeyGenerator put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES"); + put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede"); put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1"); put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224"); put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256"); @@ -88,6 +89,7 @@ public class AndroidKeyStoreProvider extends Provider { // java.security.SecretKeyFactory putSecretKeyFactoryImpl("AES"); + putSecretKeyFactoryImpl("DESede"); putSecretKeyFactoryImpl("HmacSHA1"); putSecretKeyFactoryImpl("HmacSHA224"); putSecretKeyFactoryImpl("HmacSHA256"); @@ -348,7 +350,8 @@ public class AndroidKeyStoreProvider extends Provider { } if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC || - keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES) { + keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES || + keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) { return loadAndroidKeyStoreSecretKeyFromKeystore(userKeyAlias, uid, keyCharacteristics); } else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA || diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index d73a9e29bb1b..440e0863fbb1 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -18,6 +18,7 @@ package android.security.keystore; import libcore.util.EmptyArray; import android.security.Credentials; +import android.security.GateKeeper; import android.security.KeyStore; import android.security.KeyStoreParameter; import android.security.keymaster.KeyCharacteristics; @@ -25,6 +26,7 @@ import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.security.keystore.WrappedKeyEntry; import android.util.Log; import java.io.ByteArrayInputStream; @@ -744,6 +746,31 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } } + private void setWrappedKeyEntry(String alias, byte[] wrappedKeyBytes, String wrappingKeyAlias, + java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { + if (param != null) { + throw new KeyStoreException("Protection parameters are specified inside wrapped keys"); + } + + byte[] maskingKey = new byte[32]; + KeymasterArguments args = new KeymasterArguments(); // TODO: populate wrapping key args. + + int errorCode = mKeyStore.importWrappedKey( + Credentials.USER_SECRET_KEY + alias, + wrappedKeyBytes, + Credentials.USER_PRIVATE_KEY + wrappingKeyAlias, + maskingKey, + args, + GateKeeper.getSecureUserId(), + 0, // FIXME fingerprint id? + mUid, + new KeyCharacteristics()); + if (errorCode != KeyStore.NO_ERROR) { + throw new KeyStoreException("Failed to import wrapped key. Keystore error code: " + + errorCode); + } + } + @Override public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain) throws KeyStoreException { @@ -974,6 +1001,9 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { } else if (entry instanceof SecretKeyEntry) { SecretKeyEntry secE = (SecretKeyEntry) entry; setSecretKeyEntry(alias, secE.getSecretKey(), param); + } else if (entry instanceof WrappedKeyEntry) { + WrappedKeyEntry wke = (WrappedKeyEntry) entry; + setWrappedKeyEntry(alias, wke.getWrappedKeyBytes(), wke.getWrappingKeyAlias(), param); } else { throw new KeyStoreException( "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry" diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 1238d8774e58..1e2b873c7fdd 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -262,6 +262,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { private final boolean mUniqueIdIncluded; private final boolean mUserAuthenticationValidWhileOnBody; private final boolean mInvalidatedByBiometricEnrollment; + private final boolean mIsStrongBoxBacked; /** * @hide should be built with Builder @@ -289,7 +290,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { byte[] attestationChallenge, boolean uniqueIdIncluded, boolean userAuthenticationValidWhileOnBody, - boolean invalidatedByBiometricEnrollment) { + boolean invalidatedByBiometricEnrollment, + boolean isStrongBoxBacked) { if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); } @@ -335,6 +337,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mUniqueIdIncluded = uniqueIdIncluded; mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; + mIsStrongBoxBacked = isStrongBoxBacked; } /** @@ -625,6 +628,13 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** + * Returns {@code true} if the key is protected by a Strongbox security chip. + */ + public boolean isStrongBoxBacked() { + return mIsStrongBoxBacked; + } + + /** * Builder of {@link KeyGenParameterSpec} instances. */ public final static class Builder { @@ -652,6 +662,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { private boolean mUniqueIdIncluded = false; private boolean mUserAuthenticationValidWhileOnBody; private boolean mInvalidatedByBiometricEnrollment = true; + private boolean mIsStrongBoxBacked = false; /** * Creates a new instance of the {@code Builder}. @@ -1177,6 +1188,15 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** + * Sets whether this key should be protected by a StrongBox security chip. + */ + @NonNull + public Builder setIsStrongBoxBacked(boolean isStrongBoxBacked) { + mIsStrongBoxBacked = isStrongBoxBacked; + return this; + } + + /** * Builds an instance of {@code KeyGenParameterSpec}. */ @NonNull @@ -1204,7 +1224,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mAttestationChallenge, mUniqueIdIncluded, mUserAuthenticationValidWhileOnBody, - mInvalidatedByBiometricEnrollment); + mInvalidatedByBiometricEnrollment, + mIsStrongBoxBacked); } } } diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index a250d1f01ba1..f54b6decc5c4 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -44,6 +44,7 @@ public abstract class KeyProperties { PURPOSE_DECRYPT, PURPOSE_SIGN, PURPOSE_VERIFY, + PURPOSE_WRAP_KEY, }) public @interface PurposeEnum {} @@ -68,6 +69,11 @@ public abstract class KeyProperties { public static final int PURPOSE_VERIFY = 1 << 3; /** + * Purpose of key: wrapping and unwrapping wrapped keys for secure import. + */ + public static final int PURPOSE_WRAP_KEY = 1 << 5; + + /** * @hide */ public static abstract class Purpose { @@ -83,6 +89,8 @@ public abstract class KeyProperties { return KeymasterDefs.KM_PURPOSE_SIGN; case PURPOSE_VERIFY: return KeymasterDefs.KM_PURPOSE_VERIFY; + case PURPOSE_WRAP_KEY: + return KeymasterDefs.KM_PURPOSE_WRAP; default: throw new IllegalArgumentException("Unknown purpose: " + purpose); } @@ -98,6 +106,8 @@ public abstract class KeyProperties { return PURPOSE_SIGN; case KeymasterDefs.KM_PURPOSE_VERIFY: return PURPOSE_VERIFY; + case KeymasterDefs.KM_PURPOSE_WRAP: + return PURPOSE_WRAP_KEY; default: throw new IllegalArgumentException("Unknown purpose: " + purpose); } @@ -146,6 +156,15 @@ public abstract class KeyProperties { /** Advanced Encryption Standard (AES) key. */ public static final String KEY_ALGORITHM_AES = "AES"; + /** + * Triple Data Encryption Algorithm (3DES) key. + * + * @deprecated Included for interoperability with legacy systems. Prefer {@link + * KeyProperties#KEY_ALGORITHM_AES} for new development. + */ + @Deprecated + public static final String KEY_ALGORITHM_3DES = "DESede"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */ public static final String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; @@ -196,6 +215,8 @@ public abstract class KeyProperties { @NonNull @KeyAlgorithmEnum String algorithm) { if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) { return KeymasterDefs.KM_ALGORITHM_AES; + } else if (KEY_ALGORITHM_3DES.equalsIgnoreCase(algorithm)) { + return KeymasterDefs.KM_ALGORITHM_3DES; } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) { return KeymasterDefs.KM_ALGORITHM_HMAC; } else { @@ -210,6 +231,8 @@ public abstract class KeyProperties { switch (keymasterAlgorithm) { case KeymasterDefs.KM_ALGORITHM_AES: return KEY_ALGORITHM_AES; + case KeymasterDefs.KM_ALGORITHM_3DES: + return KEY_ALGORITHM_3DES; case KeymasterDefs.KM_ALGORITHM_HMAC: switch (keymasterDigest) { case KeymasterDefs.KM_DIGEST_SHA1: @@ -666,6 +689,10 @@ public abstract class KeyProperties { */ public static final int ORIGIN_UNKNOWN = 1 << 2; + /** Key was imported into the AndroidKeyStore in an encrypted wrapper */ + public static final int ORIGIN_SECURELY_IMPORTED = 1 << 3; + + /** * @hide */ @@ -680,6 +707,8 @@ public abstract class KeyProperties { return ORIGIN_IMPORTED; case KeymasterDefs.KM_ORIGIN_UNKNOWN: return ORIGIN_UNKNOWN; + case KeymasterDefs.KM_ORIGIN_SECURELY_IMPORTED: + return ORIGIN_SECURELY_IMPORTED; default: throw new IllegalArgumentException("Unknown origin: " + origin); } diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 2eb06631c228..dbacb9c53dd6 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -488,9 +488,9 @@ public final class KeyProtection implements ProtectionParameter { private int mUserAuthenticationValidityDurationSeconds = -1; private boolean mUserAuthenticationValidWhileOnBody; private boolean mInvalidatedByBiometricEnrollment = true; - private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID; private boolean mCriticalToDeviceEncryption = false; + /** * Creates a new instance of the {@code Builder}. * diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java new file mode 100644 index 000000000000..ad41a58eb76f --- /dev/null +++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import java.security.ProviderException; + +/** + * Indicates that an operation could not be performed because the requested security hardware + * is not available. + */ +public class StrongBoxUnavailableException extends ProviderException { + +} + diff --git a/keystore/java/android/security/keystore/WrappedKeyEntry.java b/keystore/java/android/security/keystore/WrappedKeyEntry.java new file mode 100644 index 000000000000..a8f4afe7a201 --- /dev/null +++ b/keystore/java/android/security/keystore/WrappedKeyEntry.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.security.keystore; + +import java.security.KeyStore.Entry; +import java.security.spec.AlgorithmParameterSpec; + +/** + * An {@link Entry} that holds a wrapped key. + */ +public class WrappedKeyEntry implements Entry { + + private final byte[] mWrappedKeyBytes; + private final String mWrappingKeyAlias; + private final String mTransformation; + private final AlgorithmParameterSpec mAlgorithmParameterSpec; + + public WrappedKeyEntry(byte[] wrappedKeyBytes, String wrappingKeyAlias, String transformation, + AlgorithmParameterSpec algorithmParameterSpec) { + mWrappedKeyBytes = wrappedKeyBytes; + mWrappingKeyAlias = wrappingKeyAlias; + mTransformation = transformation; + mAlgorithmParameterSpec = algorithmParameterSpec; + } + + public byte[] getWrappedKeyBytes() { + return mWrappedKeyBytes; + } + + public String getWrappingKeyAlias() { + return mWrappingKeyAlias; + } + + public String getTransformation() { + return mTransformation; + } + + public AlgorithmParameterSpec getAlgorithmParameterSpec() { + return mAlgorithmParameterSpec; + } +} diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 5b95c81db24e..696a00c7b2c0 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -1877,19 +1877,27 @@ void ResTable_config::swapHtoD() { return (l.locale > r.locale) ? 1 : -1; } - // The language & region are equal, so compare the scripts and variants. + // The language & region are equal, so compare the scripts, variants and + // numbering systms in this order. Comparison of variants and numbering + // systems should happen very infrequently (if at all.) + // The comparison code relies on memcmp low-level optimizations that make it + // more efficient than strncmp. const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'}; const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript; const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript; + int script = memcmp(lScript, rScript, sizeof(l.localeScript)); if (script) { return script; } - // The language, region and script are equal, so compare variants. - // - // This should happen very infrequently (if at all.) - return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant)); + int variant = memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant)); + if (variant) { + return variant; + } + + return memcmp(l.localeNumberingSystem, r.localeNumberingSystem, + sizeof(l.localeNumberingSystem)); } int ResTable_config::compare(const ResTable_config& o) const { @@ -2030,6 +2038,22 @@ int ResTable_config::diff(const ResTable_config& o) const { return diffs; } +// There isn't a well specified "importance" order between variants and +// scripts. We can't easily tell whether, say "en-Latn-US" is more or less +// specific than "en-US-POSIX". +// +// We therefore arbitrarily decide to give priority to variants over +// scripts since it seems more useful to do so. We will consider +// "en-US-POSIX" to be more specific than "en-Latn-US". +// +// Unicode extension keywords are considered to be less important than +// scripts and variants. +inline int ResTable_config::getImportanceScoreOfLocale() const { + return (localeVariant[0] ? 4 : 0) + + (localeScript[0] && !localeScriptWasComputed ? 2: 0) + + (localeNumberingSystem[0] ? 1: 0); +} + int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const { if (locale || o.locale) { if (language[0] != o.language[0]) { @@ -2043,21 +2067,7 @@ int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const { } } - // There isn't a well specified "importance" order between variants and - // scripts. We can't easily tell whether, say "en-Latn-US" is more or less - // specific than "en-US-POSIX". - // - // We therefore arbitrarily decide to give priority to variants over - // scripts since it seems more useful to do so. We will consider - // "en-US-POSIX" to be more specific than "en-Latn-US". - - const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) + - ((localeVariant[0] != '\0') ? 2 : 0); - - const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) + - ((o.localeVariant[0] != '\0') ? 2 : 0); - - return score - oScore; + return getImportanceScoreOfLocale() - o.getImportanceScoreOfLocale(); } bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { @@ -2314,6 +2324,17 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o, return localeMatches; } + // The variants are the same, try numbering system. + const bool localeNumsysMatches = strncmp(localeNumberingSystem, + requested->localeNumberingSystem, + sizeof(localeNumberingSystem)) == 0; + const bool otherNumsysMatches = strncmp(o.localeNumberingSystem, + requested->localeNumberingSystem, + sizeof(localeNumberingSystem)) == 0; + if (localeNumsysMatches != otherNumsysMatches) { + return localeNumsysMatches; + } + // Finally, the languages, although equivalent, may still be different // (like for Tagalog and Filipino). Identical is better than just // equivalent. @@ -2781,7 +2802,7 @@ void ResTable_config::appendDirLocale(String8& out) const { return; } const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed; - if (!scriptWasProvided && !localeVariant[0]) { + if (!scriptWasProvided && !localeVariant[0] && !localeNumberingSystem[0]) { // Legacy format. if (out.size() > 0) { out.append("-"); @@ -2826,6 +2847,12 @@ void ResTable_config::appendDirLocale(String8& out) const { out.append("+"); out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant))); } + + if (localeNumberingSystem[0]) { + out.append("+u+nu+"); + out.append(localeNumberingSystem, + strnlen(localeNumberingSystem, sizeof(localeNumberingSystem))); + } } void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool canonicalize) const { @@ -2868,10 +2895,17 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool can str[charsWritten++] = '-'; } memcpy(str + charsWritten, localeVariant, sizeof(localeVariant)); + charsWritten += strnlen(str + charsWritten, sizeof(localeVariant)); } - /* TODO: Add BCP47 extension. It requires RESTABLE_MAX_LOCALE_LEN - * increase from 28 to 42 bytes (-u-nu-xxxxxxxx) */ + // Add Unicode extension only if at least one other locale component is present + if (localeNumberingSystem[0] != '\0' && charsWritten > 0) { + static constexpr char NU_PREFIX[] = "-u-nu-"; + static constexpr size_t NU_PREFIX_LEN = sizeof(NU_PREFIX) - 1; + memcpy(str + charsWritten, NU_PREFIX, NU_PREFIX_LEN); + charsWritten += NU_PREFIX_LEN; + memcpy(str + charsWritten, localeNumberingSystem, sizeof(localeNumberingSystem)); + } } struct LocaleParserState { @@ -3004,10 +3038,7 @@ struct LocaleParserState { } void ResTable_config::setBcp47Locale(const char* in) { - locale = 0; - memset(localeScript, 0, sizeof(localeScript)); - memset(localeVariant, 0, sizeof(localeVariant)); - memset(localeNumberingSystem, 0, sizeof(localeNumberingSystem)); + clearLocale(); const char* start = in; LocaleParserState state; diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 8cf4de9167e5..a1f15f0c96cb 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -894,9 +894,10 @@ struct ResTable_package // - a 8 char variant code prefixed by a 'v' // // each separated by a single char separator, which sums up to a total of 24 -// chars, (25 include the string terminator) rounded up to 28 to be 4 byte -// aligned. -#define RESTABLE_MAX_LOCALE_LEN 28 +// chars, (25 include the string terminator). Numbering system specificator, +// if present, can add up to 14 bytes (-u-nu-xxxxxxxx), giving 39 bytes, +// or 40 bytes to make it 4 bytes aligned. +#define RESTABLE_MAX_LOCALE_LEN 40 /** @@ -1303,6 +1304,9 @@ struct ResTable_config // and 0 if they're equally specific. int isLocaleMoreSpecificThan(const ResTable_config &o) const; + // Returns an integer representng the imporance score of the configuration locale. + int getImportanceScoreOfLocale() const; + // Return true if 'this' is a better locale match than 'o' for the // 'requested' configuration. Similar to isBetterThan(), this assumes that // match() has already been used to remove any configurations that don't diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp index 35007c815edd..ac08c52772d1 100644 --- a/libs/androidfw/tests/ConfigLocale_test.cpp +++ b/libs/androidfw/tests/ConfigLocale_test.cpp @@ -173,6 +173,18 @@ TEST(ConfigLocaleTest, IsMoreSpecificThan) { fillIn("en", "US", NULL, "POSIX", &r); EXPECT_FALSE(l.isMoreSpecificThan(r)); EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("ar", "EG", NULL, NULL, &l); + fillIn("ar", "EG", NULL, NULL, &r); + memcpy(&r.localeNumberingSystem, "latn", 4); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("en", "US", NULL, NULL, &l); + fillIn("es", "ES", NULL, NULL, &r); + + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_FALSE(r.isMoreSpecificThan(l)); } TEST(ConfigLocaleTest, setLocale) { @@ -321,6 +333,22 @@ TEST(ConfigLocaleTest, getBcp47Locale_script) { EXPECT_EQ(0, strcmp("en", out)); } +TEST(ConfigLocaleTest, getBcp47Locale_numberingSystem) { + ResTable_config config; + fillIn("en", NULL, NULL, NULL, &config); + + char out[RESTABLE_MAX_LOCALE_LEN]; + + memcpy(&config.localeNumberingSystem, "latn", 4); + config.getBcp47Locale(out); + EXPECT_EQ(0, strcmp("en-u-nu-latn", out)); + + fillIn("sr", "SR", "Latn", NULL, &config); + memcpy(&config.localeNumberingSystem, "latn", 4); + config.getBcp47Locale(out); + EXPECT_EQ(0, strcmp("sr-Latn-SR-u-nu-latn", out)); +} + TEST(ConfigLocaleTest, getBcp47Locale_canonicalize) { ResTable_config config; char out[RESTABLE_MAX_LOCALE_LEN]; @@ -433,6 +461,11 @@ TEST(ConfigLocaleTest, match) { fillIn("ar", "XB", NULL, NULL, &requested); // Even if they are pseudo-locales, exactly equal locales match. EXPECT_TRUE(supported.match(requested)); + + fillIn("ar", "EG", NULL, NULL, &supported); + fillIn("ar", "TN", NULL, NULL, &requested); + memcpy(&supported.localeNumberingSystem, "latn", 4); + EXPECT_TRUE(supported.match(requested)); } TEST(ConfigLocaleTest, match_emptyScript) { @@ -758,6 +791,26 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) { EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); } +TEST(ConfigLocaleTest, isLocaleBetterThan_numberingSystem) { + ResTable_config config1, config2, request; + + fillIn("ar", "EG", NULL, NULL, &request); + memcpy(&request.localeNumberingSystem, "latn", 4); + fillIn("ar", NULL, NULL, NULL, &config1); + memcpy(&config1.localeNumberingSystem, "latn", 4); + fillIn("ar", NULL, NULL, NULL, &config2); + EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); + EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); + + fillIn("ar", "EG", NULL, NULL, &request); + memcpy(&request.localeNumberingSystem, "latn", 4); + fillIn("ar", "TN", NULL, NULL, &config1); + memcpy(&config1.localeNumberingSystem, "latn", 4); + fillIn("ar", NULL, NULL, NULL, &config2); + EXPECT_TRUE(config2.isLocaleBetterThan(config1, &request)); + EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request)); +} + // Default resources are considered better matches for US English // and US-like English locales than International English locales TEST(ConfigLocaleTest, isLocaleBetterThan_UsEnglishIsSpecial) { diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index e2f9b47ed482..690d74040ce1 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -16,13 +16,6 @@ package android.media; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -34,6 +27,16 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.util.Log; +import dalvik.system.CloseGuard; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + /** * MediaDrm can be used to obtain keys for decrypting protected media streams, in @@ -117,10 +120,13 @@ import android.util.Log; * MediaDrm objects on a thread with its own Looper running (main UI * thread by default has a Looper running). */ -public final class MediaDrm { +public final class MediaDrm implements AutoCloseable { private static final String TAG = "MediaDrm"; + private final AtomicBoolean mClosed = new AtomicBoolean(); + private final CloseGuard mCloseGuard = CloseGuard.get(); + private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private EventHandler mEventHandler; @@ -215,6 +221,8 @@ public final class MediaDrm { */ native_setup(new WeakReference<MediaDrm>(this), getByteArrayFromUUID(uuid), ActivityThread.currentOpPackageName()); + + mCloseGuard.open("release"); } /** @@ -954,6 +962,168 @@ public final class MediaDrm { */ public native void releaseAllSecureStops(); + @Retention(RetentionPolicy.SOURCE) + @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2, + HDCP_V2_1, HDCP_V2_2, HDCP_NO_DIGITAL_OUTPUT}) + public @interface HdcpLevel {} + + + /** + * The DRM plugin did not report an HDCP level, or an error + * occurred accessing it + */ + public static final int HDCP_LEVEL_UNKNOWN = 0; + + /** + * HDCP is not supported on this device, content is unprotected + */ + public static final int HDCP_NONE = 1; + + /** + * HDCP version 1.0 + */ + public static final int HDCP_V1 = 2; + + /** + * HDCP version 2.0 Type 1. + */ + public static final int HDCP_V2 = 3; + + /** + * HDCP version 2.1 Type 1. + */ + public static final int HDCP_V2_1 = 4; + + /** + * HDCP version 2.2 Type 1. + */ + public static final int HDCP_V2_2 = 5; + + /** + * No digital output, implicitly secure + */ + public static final int HDCP_NO_DIGITAL_OUTPUT = Integer.MAX_VALUE; + + /** + * Return the HDCP level negotiated with downstream receivers the + * device is connected to. If multiple HDCP-capable displays are + * simultaneously connected to separate interfaces, this method + * returns the lowest negotiated level of all interfaces. + * <p> + * This method should only be used for informational purposes, not for + * enforcing compliance with HDCP requirements. Trusted enforcement of + * HDCP policies must be handled by the DRM system. + * <p> + * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE}, + * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2} + * or {@link #HDCP_NO_DIGITAL_OUTPUT}. + */ + @HdcpLevel + public native int getConnectedHdcpLevel(); + + /** + * Return the maximum supported HDCP level. The maximum HDCP level is a + * constant for a given device, it does not depend on downstream receivers + * that may be connected. If multiple HDCP-capable interfaces are present, + * it indicates the highest of the maximum HDCP levels of all interfaces. + * <p> + * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE}, + * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2} + * or {@link #HDCP_NO_DIGITAL_OUTPUT}. + */ + @HdcpLevel + public native int getMaxHdcpLevel(); + + /** + * Return the number of MediaDrm sessions that are currently opened + * simultaneously among all MediaDrm instances for the active DRM scheme. + * @return the number of open sessions. + */ + public native int getOpenSessionCount(); + + /** + * Return the maximum number of MediaDrm sessions that may be opened + * simultaneosly among all MediaDrm instances for the active DRM + * scheme. The maximum number of sessions is not affected by any + * sessions that may have already been opened. + * @return maximum sessions. + */ + public native int getMaxSessionCount(); + + /** + * Security level indicates the robustness of the device's DRM + * implementation. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE, + HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL}) + public @interface SecurityLevel {} + + /** + * The DRM plugin did not report a security level, or an error occurred + * accessing it + */ + public static final int SECURITY_LEVEL_UNKNOWN = 0; + + /** + * Software-based whitebox crypto + */ + public static final int SW_SECURE_CRYPTO = 1; + + /** + * Software-based whitebox crypto and an obfuscated decoder + */ + public static final int SW_SECURE_DECODE = 2; + + /** + * DRM key management and crypto operations are performed within a + * hardware backed trusted execution environment + */ + public static final int HW_SECURE_CRYPTO = 3; + + /** + * DRM key management, crypto operations and decoding of content + * are performed within a hardware backed trusted execution environment + */ + public static final int HW_SECURE_DECODE = 4; + + /** + * DRM key management, crypto operations, decoding of content and all + * handling of the media (compressed and uncompressed) is handled within + * a hardware backed trusted execution environment. + */ + public static final int HW_SECURE_ALL = 5; + + /** + * Return the current security level of a session. A session + * has an initial security level determined by the robustness of + * the DRM system's implementation on the device. The security + * level may be adjusted using {@link #setSecurityLevel}. + * @param sessionId the session to query. + * <p> + * @return one of {@link #SECURITY_LEVEL_UNKNOWN}, + * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE}, + * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or + * {@link #HW_SECURE_ALL}. + */ + @SecurityLevel + public native int getSecurityLevel(@NonNull byte[] sessionId); + + /** + * Set the security level of a session. This can be useful if specific + * attributes of a lower security level are needed by an application, + * such as image manipulation or compositing. Reducing the security + * level will typically limit decryption to lower content resolutions, + * depending on the license policy. + * @param sessionId the session to set the security level on. + * @param level the new security level, one of + * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE}, + * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or + * {@link #HW_SECURE_ALL}. + */ + public native void setSecurityLevel(@NonNull byte[] sessionId, + @SecurityLevel int level); + /** * String property name: identifies the maker of the DRM plugin */ @@ -1311,18 +1481,52 @@ public final class MediaDrm { } @Override - protected void finalize() { - native_finalize(); + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + release(); + } finally { + super.finalize(); + } } - public native final void release(); + /** + * Releases resources associated with the current session of + * MediaDrm. It is considered good practice to call this method when + * the {@link MediaDrm} object is no longer needed in your + * application. After this method is called, {@link MediaDrm} is no + * longer usable since it has lost all of its required resource. + * + * This method was added in API 28. In API versions 18 through 27, release() + * should be called instead. There is no need to do anything for API + * versions prior to 18. + */ + @Override + public void close() { + release(); + } + + /** + * @deprecated replaced by {@link #close()}. + */ + @Deprecated + public void release() { + mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { + native_release(); + } + } + + /** @hide */ + public native final void native_release(); + private static native final void native_init(); private native final void native_setup(Object mediadrm_this, byte[] uuid, String appPackageName); - private native final void native_finalize(); - static { System.loadLibrary("media_jni"); native_init(); diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 51c9e5f1c7da..1dddbeed608c 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -130,6 +130,26 @@ struct StateExceptionFields { jclass classId; }; +struct HDCPLevels { + jint kHdcpLevelUnknown; + jint kHdcpNone; + jint kHdcpV1; + jint kHdcpV2; + jint kHdcpV2_1; + jint kHdcpV2_2; + jint kHdcpNoOutput; +} gHdcpLevels; + +struct SecurityLevels { + jint kSecurityLevelUnknown; + jint kSecurityLevelSwSecureCrypto; + jint kSecurityLevelSwSecureDecode; + jint kSecurityLevelHwSecureCrypto; + jint kSecurityLevelHwSecureDecode; + jint kSecurityLevelHwSecureAll; +} gSecurityLevels; + + struct fields_t { jfieldID context; jmethodID post_event; @@ -565,12 +585,19 @@ static sp<JDrm> setDrm( return old; } -static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId) -{ +static bool CheckDrm(JNIEnv *env, const sp<IDrm> &drm) { if (drm == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "MediaDrm obj is null"); return false; } + return true; +} + +static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId) +{ + if (!CheckDrm(env, drm)) { + return false; + } if (jsessionId == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", "sessionId is null"); @@ -579,7 +606,7 @@ static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jse return true; } -static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) { +static void android_media_MediaDrm_native_release(JNIEnv *env, jobject thiz) { sp<JDrm> drm = setDrm(env, thiz, NULL); if (drm != NULL) { drm->setListener(NULL); @@ -625,6 +652,34 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I"); gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_LEVEL_UNKNOWN", "I"); + gHdcpLevels.kHdcpLevelUnknown = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_NONE", "I"); + gHdcpLevels.kHdcpNone = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_V1", "I"); + gHdcpLevels.kHdcpV1 = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2", "I"); + gHdcpLevels.kHdcpV2 = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_1", "I"); + gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I"); + gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I"); + gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field); + + GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I"); + gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_CRYPTO", "I"); + gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_DECODE", "I"); + gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_CRYPTO", "I"); + gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_DECODE", "I"); + gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field); + GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I"); + gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field); + FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); @@ -724,11 +779,6 @@ static void android_media_MediaDrm_native_setup( setDrm(env, thiz, drm); } -static void android_media_MediaDrm_native_finalize( - JNIEnv *env, jobject thiz) { - android_media_MediaDrm_release(env, thiz); -} - static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) { @@ -971,9 +1021,7 @@ static jobject android_media_MediaDrm_getProvisionRequestNative( JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1018,9 +1066,7 @@ static jobject android_media_MediaDrm_provideProvisionResponseNative( JNIEnv *env, jobject thiz, jbyteArray jresponse) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1057,9 +1103,7 @@ static jobject android_media_MediaDrm_getSecureStops( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1078,9 +1122,7 @@ static jbyteArray android_media_MediaDrm_getSecureStop( JNIEnv *env, jobject thiz, jbyteArray ssid) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1099,9 +1141,7 @@ static void android_media_MediaDrm_releaseSecureStops( JNIEnv *env, jobject thiz, jbyteArray jssRelease) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return; } @@ -1116,9 +1156,7 @@ static void android_media_MediaDrm_releaseAllSecureStops( JNIEnv *env, jobject thiz) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return; } @@ -1127,13 +1165,173 @@ static void android_media_MediaDrm_releaseAllSecureStops( throwExceptionAsNecessary(env, err, "Failed to release all secure stops"); } + +static jint HdcpLevelTojint(DrmPlugin::HdcpLevel level) { + switch(level) { + case DrmPlugin::kHdcpLevelUnknown: + return gHdcpLevels.kHdcpLevelUnknown; + case DrmPlugin::kHdcpNone: + return gHdcpLevels.kHdcpNone; + case DrmPlugin::kHdcpV1: + return gHdcpLevels.kHdcpV1; + case DrmPlugin::kHdcpV2: + return gHdcpLevels.kHdcpV2; + case DrmPlugin::kHdcpV2_1: + return gHdcpLevels.kHdcpV2_1; + case DrmPlugin::kHdcpV2_2: + return gHdcpLevels.kHdcpV2_2; + case DrmPlugin::kHdcpNoOutput: + return gHdcpLevels.kHdcpNoOutput; + } + return gHdcpLevels.kHdcpNone; +} + +static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env, + jobject thiz) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckDrm(env, drm)) { + return gHdcpLevels.kHdcpNone; + } + + DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpNone; + DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpNone; + + status_t err = drm->getHdcpLevels(&connected, &max); + + if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) { + return gHdcpLevels.kHdcpLevelUnknown; + } + return HdcpLevelTojint(connected); +} + +static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env, + jobject thiz) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckDrm(env, drm)) { + return gHdcpLevels.kHdcpLevelUnknown; + } + + DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown; + DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown; + + status_t err = drm->getHdcpLevels(&connected, &max); + + if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) { + return gHdcpLevels.kHdcpLevelUnknown; + } + return HdcpLevelTojint(max); +} + +static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env, + jobject thiz) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckDrm(env, drm)) { + return 0; + } + + uint32_t open = 0, max = 0; + status_t err = drm->getNumberOfSessions(&open, &max); + + if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) { + return 0; + } + return open; +} + +static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env, + jobject thiz) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckDrm(env, drm)) { + return 0; + } + + uint32_t open = 0, max = 0; + status_t err = drm->getNumberOfSessions(&open, &max); + + if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) { + return 0; + } + return max; +} + +static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env, + jobject thiz, jbyteArray jsessionId) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckSession(env, drm, jsessionId)) { + return gSecurityLevels.kSecurityLevelUnknown; + } + + Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); + + DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown; + + status_t err = drm->getSecurityLevel(sessionId, &level); + + if (throwExceptionAsNecessary(env, err, "Failed to get security level")) { + return gSecurityLevels.kSecurityLevelUnknown; + } + + switch(level) { + case DrmPlugin::kSecurityLevelSwSecureCrypto: + return gSecurityLevels.kSecurityLevelSwSecureCrypto; + case DrmPlugin::kSecurityLevelSwSecureDecode: + return gSecurityLevels.kSecurityLevelSwSecureDecode; + case DrmPlugin::kSecurityLevelHwSecureCrypto: + return gSecurityLevels.kSecurityLevelHwSecureCrypto; + case DrmPlugin::kSecurityLevelHwSecureDecode: + return gSecurityLevels.kSecurityLevelHwSecureDecode; + case DrmPlugin::kSecurityLevelHwSecureAll: + return gSecurityLevels.kSecurityLevelHwSecureAll; + default: + return gSecurityLevels.kSecurityLevelUnknown; + } +} + + +static void android_media_MediaDrm_setSecurityLevel(JNIEnv *env, + jobject thiz, jbyteArray jsessionId, jint jlevel) { + sp<IDrm> drm = GetDrm(env, thiz); + + if (!CheckSession(env, drm, jsessionId)) { + return; + } + + Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId)); + DrmPlugin::SecurityLevel level; + + if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) { + level = DrmPlugin::kSecurityLevelSwSecureCrypto; + } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) { + level = DrmPlugin::kSecurityLevelSwSecureDecode; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) { + level = DrmPlugin::kSecurityLevelHwSecureCrypto; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) { + level = DrmPlugin::kSecurityLevelHwSecureDecode; + } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) { + level = DrmPlugin::kSecurityLevelHwSecureAll; + } else { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level"); + return; + } + + status_t err = drm->setSecurityLevel(sessionId, level); + + if (throwExceptionAsNecessary(env, err, "Failed to set security level")) { + return; + } +} + + static jstring android_media_MediaDrm_getPropertyString( JNIEnv *env, jobject thiz, jstring jname) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1159,9 +1357,7 @@ static jbyteArray android_media_MediaDrm_getPropertyByteArray( JNIEnv *env, jobject thiz, jstring jname) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return NULL; } @@ -1187,9 +1383,7 @@ static void android_media_MediaDrm_setPropertyString( JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return; } @@ -1217,9 +1411,7 @@ static void android_media_MediaDrm_setPropertyByteArray( JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) { sp<IDrm> drm = GetDrm(env, thiz); - if (drm == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "MediaDrm obj is null"); + if (!CheckDrm(env, drm)) { return; } @@ -1445,15 +1637,13 @@ static jbyteArray android_media_MediaDrm_signRSANative( static const JNINativeMethod gMethods[] = { - { "release", "()V", (void *)android_media_MediaDrm_release }, + { "native_release", "()V", (void *)android_media_MediaDrm_native_release }, + { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V", (void *)android_media_MediaDrm_native_setup }, - { "native_finalize", "()V", - (void *)android_media_MediaDrm_native_finalize }, - { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, @@ -1497,6 +1687,24 @@ static const JNINativeMethod gMethods[] = { { "releaseAllSecureStops", "()V", (void *)android_media_MediaDrm_releaseAllSecureStops }, + { "getConnectedHdcpLevel", "()I", + (void *)android_media_MediaDrm_getConnectedHdcpLevel }, + + { "getMaxHdcpLevel", "()I", + (void *)android_media_MediaDrm_getMaxHdcpLevel }, + + { "getOpenSessionCount", "()I", + (void *)android_media_MediaDrm_getOpenSessionCount }, + + { "getMaxSessionCount", "()I", + (void *)android_media_MediaDrm_getMaxSessionCount }, + + { "getSecurityLevel", "([B)I", + (void *)android_media_MediaDrm_getSecurityLevel }, + + { "setSecurityLevel", "([BI)V", + (void *)android_media_MediaDrm_setSecurityLevel }, + { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaDrm_getPropertyString }, diff --git a/packages/SettingsLib/res/drawable/btn_borderless_rect.xml b/packages/SettingsLib/res/drawable/btn_borderless_rect.xml new file mode 100644 index 000000000000..9eaba8364f8e --- /dev/null +++ b/packages/SettingsLib/res/drawable/btn_borderless_rect.xml @@ -0,0 +1,31 @@ +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<inset + xmlns:android="http://schemas.android.com/apk/res/android" + android:insetTop="4dp" + android:insetBottom="4dp"> + <ripple + android:color="?android:attr/colorControlHighlight" > + + <item android:id="@android:id/mask"> + <shape> + <corners android:radius="2dp" /> + <solid android:color="@android:color/white" /> + </shape> + </item> + + </ripple> +</inset>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_minus.xml b/packages/SettingsLib/res/drawable/ic_minus.xml new file mode 100644 index 000000000000..9a929a44c665 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_minus.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24.0dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0" + android:width="24.0dp" > + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18,13H6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h12c0.55,0 1,0.45 1,1v0C19,12.55 18.55,13 18,13z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_plus.xml b/packages/SettingsLib/res/drawable/ic_plus.xml new file mode 100644 index 000000000000..2a10e707df2a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_plus.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24.0dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0" + android:width="24.0dp" > + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18,13h-5v5c0,0.55 -0.45,1 -1,1h0c-0.55,0 -1,-0.45 -1,-1v-5H6c-0.55,0 -1,-0.45 -1,-1v0c0,-0.55 0.45,-1 1,-1h5V6c0,-0.55 0.45,-1 1,-1h0c0.55,0 1,0.45 1,1v5h5c0.55,0 1,0.45 1,1v0C19,12.55 18.55,13 18,13z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/layout/zen_mode_condition.xml b/packages/SettingsLib/res/layout/zen_mode_condition.xml new file mode 100644 index 000000000000..c85a8922a552 --- /dev/null +++ b/packages/SettingsLib/res/layout/zen_mode_condition.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:layout_marginStart="1dp" + android:layout_marginEnd="0dp" + android:layout_weight="1" + android:gravity="center_vertical" > + + <LinearLayout + android:id="@android:id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:gravity="center_vertical" + android:layout_centerVertical="true" + android:orientation="vertical" + android:layout_toEndOf="@android:id/checkbox" + android:layout_toStartOf="@android:id/button1"> + + <TextView + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:textAlignment="viewStart" + android:maxLines="1" + android:textColor="?android:attr/textColorPrimary" + android:textSize="16sp"/> + + <TextView + android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/zen_mode_condition_detail_item_interline_spacing" + android:ellipsize="end" + android:textAlignment="viewStart" + android:maxLines="1" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp"/> + + </LinearLayout> + + <ImageView + android:id="@android:id/button1" + style="@style/BorderlessButton" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_centerVertical="true" + android:scaleType="center" + android:layout_toStartOf="@android:id/button2" + android:contentDescription="@string/accessibility_manual_zen_less_time" + android:tint="?android:attr/colorAccent" + android:src="@drawable/ic_minus" /> + + <ImageView + android:id="@android:id/button2" + style="@style/BorderlessButton" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_alignParentEnd="true" + android:scaleType="center" + android:layout_centerVertical="true" + android:contentDescription="@string/accessibility_manual_zen_more_time" + android:tint="?android:attr/colorAccent" + android:src="@drawable/ic_plus" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/res/layout/zen_mode_radio_button.xml b/packages/SettingsLib/res/layout/zen_mode_radio_button.xml new file mode 100644 index 000000000000..4c0faed610f7 --- /dev/null +++ b/packages/SettingsLib/res/layout/zen_mode_radio_button.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RadioButton + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/checkbox" + android:layout_width="40dp" + android:layout_marginStart="7dp" + android:layout_marginEnd="4dp" + android:layout_height="48dp" + android:layout_alignParentStart="true" + android:gravity="center" + android:paddingTop="10dp" + android:paddingBottom="10dp"> + +</RadioButton>
\ No newline at end of file diff --git a/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml b/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml new file mode 100644 index 000000000000..ac56a2d9d2c3 --- /dev/null +++ b/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport ="true" + android:orientation="vertical"> + + <com.android.settingslib.notification.ZenRadioLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/zen_conditions" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginEnd="4dp" + android:layout_marginStart="4dp" + android:paddingBottom="4dp" + android:orientation="horizontal"> + <RadioGroup + android:id="@+id/zen_radio_buttons" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + <LinearLayout + android:id="@+id/zen_radio_buttons_content" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"/> + </com.android.settingslib.notification.ZenRadioLayout> + +</ScrollView>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index ff81fc17698c..93c0e1007aa6 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Inligtingruiling"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Draadlose skermsertifisering"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktiveer Wi-Fi-woordryke aanmelding"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressiewe Wi‑Fi-na-mobiel-oorhandiging"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Laat altyd Wi-Fi-swerfskanderings toe"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiele data is altyd aktief"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardewareversnelling vir verbinding"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Voer gasheernaam van DNS-verskaffer in"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wanneer dit geaktiveer is, sal Wi-Fi die dataverbinding aggressiewer na mobiel oordra wanneer die Wi-Fi-sein swak is"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Laat toe of verbied Wi-Fi-swerfskanderings op grond van die hoeveelheid dataverkeer wat op die koppelvlak teenwoordig is"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Loggerbuffer se groottes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Kies loggergroottes per logbuffer"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 111b7cf9eaf3..83fd2afc4787 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"አውታረ መረብ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"የWi‑Fi ተጨማሪ ቃላት ምዝግብ ማስታወሻ መያዝ"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"አስገዳጅ ከWi‑Fi ወደ ሞባይል ማቀበል"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ሁልጊዜ የWi‑Fi ማንቀሳቀስ ቅኝቶችን ይፍቀዱ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"የተንቀሳቃሽ ስልክ ውሂብ ሁልጊዜ ገቢር ነው"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"የዲኤንኤስ አቅራቢ አስተናጋጅ ስም ያስገቡ"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ሲነቃ የWi‑Fi ምልክት ዝቅተኛ ሲሆን Wi‑Fi የውሂብ ግንኙነት ለሞባይል ማስረከብ ላይ ይበልጥ አስገዳጅ ይሆናል"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"በበይነገጹ ላይ ባለው የውሂብ ትራፊክ መጠን ላይ ተመስርተው የWi‑Fi ማንቀሳቀስ ቅኝቶችን ይፍቀዱ/ይከልክሉ"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"የምዝግብ ማስታወሻ ያዥ መጠኖች"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"በአንድ ምዝግብ ማስታወሻ ቋጥ የሚኖረው የምዝግብ ማስታወሻ ያዥ መጠኖች ይምረጡ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index b101a1d2bea2..a541cbd62317 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"الشبكات"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"شهادة عرض شاشة لاسلكي"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"تمكين تسجيل Wi‑Fi Verbose"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"تسليم Wi-Fi حاد إلى جوّال"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"السماح دائمًا بعمليات فحص Wi-Fi للتجوال"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"بيانات الجوّال نشطة دائمًا"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"تسريع الأجهزة للتوصيل"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"أدخل اسم مضيف مزوّد نظام أسماء النطاقات"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"عرض خيارات شهادة عرض شاشة لاسلكي"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"عند تمكينه، سيكون Wi-Fi أكثر حدة في تسليم اتصال البيانات إلى الجوّال، وذلك عندما تكون إشارة WiFi منخفضة"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"السماح/عدم السماح بعمليات فحص Wi-Fi للتجوال بناءً على حجم حركة البيانات في الواجهة"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"حدد أحجامًا أكبر لكل ذاكرة تخزين مؤقت للتسجيل"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 03c9b9225a5c..5b4e45ced376 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Şəbəkələşmə"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Simsiz displey sertifikatlaşması"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi Çoxsözlü Girişə icazə verin"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Möbül ötürücüyə aqressiv Wi‑Fi"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi axtarışlarına həmişə icazə verin"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil data həmişə aktiv"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Birləşmə üçün avadanlıq akselerasiyası"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderinin host adını daxil edin"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Aktiv edildikdə, Wi-Fi siqnalı zəif olan zaman, data bağlantısını mobilə ötürərəkən Wi-Fi daha aqressiv olacaq"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Wi‑Fi Axtarışlarına data trafikinə əsasən İcazə verin/Qadağan edin"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger bufer ölçüləri"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Hər jurnal buferinı Logger ölçüsü seçin"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 62e4b4c6b08a..0545021b159d 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Sertifikacija bežičnog ekrana"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljniju evidenciju za Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresivan prelaz sa Wi‑Fi mreže na mobilnu"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilni podaci su uvek aktivni"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje privezivanja"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite ime hosta dobavljača usluge DNS-a"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kad se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na mobilnu ako je Wi‑Fi signal slab"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/zabrani skeniranje Wi-Fi-ja u romingu na osnovu prisutnog protoka podataka na interfejsu"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera podataka u programu za evidentiranje"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Izaberite veličine po baferu evidencije"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index c648ea5ace03..05be22280f81 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Сеткі"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Сертыфікацыя бесправаднога дысплея"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Уключыць падрабязны журнал Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Інтэнсіўны пераход з Wi‑Fi на маб. сетку"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Заўсёды дазваляць роўмінгавае сканіраванне Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мабільная перадача даных заўсёды актыўная"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратнае паскарэнне ў рэжыме мадэма"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Увядзіце імя вузла аператара DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Падвыс. узровень дэтал-цыі журнала Wi‑Fi у залежн. ад SSID RSSI у Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Калі гэта функцыя ўключана, Wi-Fi будзе больш інтэнсіўна імкнуцца перайсці на падключ. маб. перад. даных пры слабым сігнале Wi‑Fi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Дазволіць/забараніць роўмінгавае сканіраванне Wi‑Fi ў залежнасці ад аб\'ёму трафіку даных у інтэрфейсе"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Памеры буфера для сродку вядзення журнала"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Выберыце памеры сродку вядзення журнала для буфераў журнала"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 83c1ec0b0ab7..ea67a980590d 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Мрежи"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Безжичен дисплей"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"„Многословно“ регистр. на Wi‑Fi: Актив."</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi-Fi към моб. мрежи: Агресивно предав."</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Сканирането за роуминг на Wi-Fi да е разрешено винаги"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Винаги активни мобилни данни"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардуерно ускорение за тетъринга"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Въведете името на хоста на DNS доставчика"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"При активиране предаването на връзката за данни от Wi-Fi към мобилната мрежа ще е по-агресивно, когато сигналът за Wi-Fi е слаб"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Разрешаване/забраняване на сканирането за роуминг на Wi-Fi въз основа на посочения в интерфейса обем на трафика на данни"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Размери на регистрац. буфери"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Размер на един рег. буфер: Избор"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index baf9e2c91fc4..f30ed2b87791 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"নেটওয়ার্কিং"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ওয়্যারলেস ডিসপ্লে সার্টিফিকেশন"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"ওয়াই-ফাই ভারবোস লগিং সক্ষম করুন"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ওয়াই-ফাই থেকে মোবাইলে তৎপর হস্তান্তর"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"সর্বদা ওয়াই ফাই রোম স্ক্যানকে অনুমতি দিন"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএস প্রদানকারীর হোস্টনেম লিখুন"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"সক্ষম করা থাকলে, ওয়াই ফাই সিগন্যালের মান খারাপ হলে ডেটা সংযোগ মোবাইলের কাছে হস্তান্তর করার জন্য ওয়াই ফাই আরো বেশি তৎপর হবে।"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ইন্টারফেসে উপস্থিত ডেটা ট্রাফিকের পরিমাণের উপরে ভিত্তি করে ওয়াই-ফাই রোম স্ক্যানকে অনুমোদিত/অননুমোদিত করুন"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"লগার বাফারের আকারগুলি"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"লগ বাফার প্রতি অপেক্ষাকৃত বড় আকারগুলির বেছে নিন"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 88b01e9877a9..915eb4917bd1 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikacija bežičnog prikaza"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogućiti Wi-Fi Verbose zapisivanje"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresivni prijenos s Wi-Fi mreže na mob."</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopustiti Wi-Fi lutajuće skeniranje"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna mreža za prijenos podataka je uvijek aktivna"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje dijeljenja veze"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv host računara pružaoca DNS-a"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kada je omogućeno, Wi-Fi veza će u slučaju slabog signala agresivnije predavati vezu za prijenos podataka na mobilnu vezu"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/Zabrani Wi-Fi lutajuće skeniranje na osnovu količine podatkovnog saobraćaja prisutnog na interfejsu"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera za zapisnik"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličine za Logger prema međumemoriji evidencije"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 48223ce614ba..d8c66933310e 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Xarxes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificació de pantalla sense fil"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Activa el registre Wi‑Fi detallat"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferència agressiva de Wi-Fi a mòbil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dades mòbils sempre actives"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per compartir la xarxa"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introdueix el nom d\'amfitrió del proveïdor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quan s\'activa, la Wi-Fi és més agressiva en transferir la connexió de dades al mòbil quan el senyal de la Wi-Fi sigui dèbil"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permet/No permetis cerques de xarxes Wi-Fi en itinerància basades en la quantitat de dades presents a la interfície"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Mides memòria intermèdia Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Mida Logger per memòria intermèdia"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 88bbaa77399f..41ff8e23f83c 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Sítě"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikace bezdrát. displeje"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Podrobné protokolování Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresivní předání z Wi-Fi na mobilní síť"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povolit Wi-Fi roaming"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilní data jsou vždy aktivní"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarová akcelerace tetheringu"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadejte název hostitele poskytovatele DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Pokud je tato možnost zapnuta, bude síť Wi-Fi při předávání datového připojení mobilní síti při slabém signálu Wi-Fi agresivnější."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Povolí nebo zakáže Wi-Fi roaming na základě množství datového provozu na rozhraní."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Vyrovnávací paměť protokol. nástroje"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Velikost vyrovnávací paměti protokol. nástroje"</string> @@ -395,7 +393,7 @@ <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string> <string name="retail_demo_reset_message" msgid="118771671364131297">"Chcete-li v ukázkovém režimu obnovit zařízení do továrního nastavení, zadejte heslo"</string> <string name="retail_demo_reset_next" msgid="8356731459226304963">"Další"</string> - <string name="retail_demo_reset_title" msgid="696589204029930100">"Je třeba zadat heslo"</string> + <string name="retail_demo_reset_title" msgid="696589204029930100">"Zadejte heslo"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Aktivní metody zadávání"</string> <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Použít systémové jazyky"</string> <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Nastavení aplikace <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> se nepodařilo otevřít"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 6f36bc563e3a..17d1f083ecb3 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Netværk"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificering af trådløs skærm"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktivér detaljeret Wi-Fi-logføring"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Tvungen skift fra Wi-Fi til mobildata"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillad altid scanning af Wi-Fi-roaming"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata er altid aktiveret"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareacceleration ved netdeling"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Angiv hostname for DNS-udbyder"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Når dette er aktiveret, gennemtvinges en overdragelse af dataforbindelsen fra Wi-Fi til mobilnetværk, når Wi-Fi-signalet er svagt"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Tillad/forbyd scanning i forbindelse med Wi-Fi-roaming afhængigt af mængden af datatrafik i grænsefladen"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Størrelser for Logger-buffer"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Vælg Logger-størrelser pr. logbuffer"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 4d53e2dd07bb..2fbac9315979 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Netzwerke"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Kabellose Übertragung"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ausführliche WLAN-Protokolle aktivieren"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressives Handover von WLAN an Mobilfunk"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"WLAN-Roamingsuchen immer zulassen"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile Datennutzung immer aktiviert"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarebeschleunigung für Tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Hostname des DNS-Anbieters eingeben"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Level für WLAN-Protokollierung erhöhen, in WiFi Picker pro SSID-RSSI anzeigen"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wenn diese Option aktiviert ist, ist das WLAN bei schwachem Signal bei der Übergabe der Datenverbindung an den Mobilfunk aggressiver"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"WLAN-Roamingsuchen je nach Umfang des Datentraffics an der Schnittstelle zulassen bzw. nicht zulassen"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger-Puffergrößen"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Größe pro Protokollpuffer wählen"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index e5103564d0cc..25de91426de7 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Δικτύωση"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Πιστοποίηση ασύρματης οθόνης"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ενεργοποίηση λεπτομερ. καταγραφής Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Επιθ.μεταβ. Wi-Fi σε δίκτυο κιν.τηλ."</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Να επιτρέπεται πάντα η σάρωση Wi-Fi κατά την περιαγωγή"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Σύνδεση επιτάχυνσης υλικού"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Εισαγάγετε το όνομα κεντρικού υπολογιστή του παρόχου DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Όταν είναι ενεργό, το Wi-Fi θα μεταβιβάζει πιο επιθετικά τη σύνδ.δεδομένων σε δίκτυο κινητής τηλ., όταν το σήμα Wi-Fi είναι χαμηλό"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Να επιτρέπεται/να μην επιτρέπεται η σάρωση Wi-Fi κατά την περιαγωγή, βάσει της ποσότητας επισκεψιμότητας δεδομένων στη διεπαφή"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Μέγεθος προσωρινής μνήμης για τη λειτουργία καταγραφής"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Μέγεθος αρχείων κατ/φής ανά προ/νή μνήμη αρχείου κατ/φής"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index a32238898bc7..9f5353f4b1cd 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Enable Wi‑Fi verbose logging"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressive Wi‑Fi to mobile handover"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Allow/Disallow Wi‑Fi Roam Scans based on the amount of data traffic present at the interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger buffer sizes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Select Logger sizes per log buffer"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index a32238898bc7..9f5353f4b1cd 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Enable Wi‑Fi verbose logging"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressive Wi‑Fi to mobile handover"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Allow/Disallow Wi‑Fi Roam Scans based on the amount of data traffic present at the interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger buffer sizes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Select Logger sizes per log buffer"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index a32238898bc7..9f5353f4b1cd 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Enable Wi‑Fi verbose logging"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressive Wi‑Fi to mobile handover"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Allow/Disallow Wi‑Fi Roam Scans based on the amount of data traffic present at the interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger buffer sizes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Select Logger sizes per log buffer"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index a32238898bc7..9f5353f4b1cd 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Enable Wi‑Fi verbose logging"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressive Wi‑Fi to mobile handover"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Allow/Disallow Wi‑Fi Roam Scans based on the amount of data traffic present at the interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger buffer sizes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Select Logger sizes per log buffer"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 80c2eb8b3eb1..a8561fab9f47 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Enable Wi‑Fi Verbose Logging"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressive Wi‑Fi to mobile handover"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Allow/Disallow Wi‑Fi Roam Scans based on the amount of data traffic present at the interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger buffer sizes"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Select Logger sizes per log buffer"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 65000b375d8f..eeaf18fdac07 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Habilitar registro detallado de Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Priorizar cambio de red Wi-Fi a móvil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activados"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware de conexión mediante dispositivo portátil"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ingresa el nombre de host del proveedor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si habilitas esta opción, se priorizará el cambio de Wi-Fi a datos móviles cuando la señal de Wi-Fi sea débil"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/no permitir las búsquedas de Wi-Fi basadas la cantidad de tráfico de datos presente en la interfaz"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Selecciona el tamaño del Logger por búfer"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 2a5e41b536b0..97d9a1020967 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Habilitar registro Wi-Fi detallado"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferencia agresiva de Wi-Fi a móvil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión compartida"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce el nombre de host del proveedor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de registro de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si se activa esta opción, la conexión Wi-Fi será más agresiva al pasar la conexión a datos móviles (si la señal Wi-Fi es débil)"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/No permitir búsquedas de Wi-Fi basadas en la cantidad de tráfico de datos presente en la interfaz"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de registrador"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index a8ac99f896ff..b680b843919a 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Võrgustik"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Juhtmeta ekraaniühenduse sertifitseerimine"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Luba WiFi paljusõnaline logimine"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agress. üleminek WiFi-lt mobiilsidele"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luba alati WiFi-rändluse skannimine"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiilne andmeside on alati aktiivne"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Jagamise riistvaraline kiirendus"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Sisestage DNS-i teenusepakkuja hostinimi"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kui seade on lubatud, asendatakse nõrga signaaliga WiFi-ühendus agressiivsemalt mobiilse andmesideühendusega"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Luba/keela WiFi-rändluse skannimine liidese andmeliikluse põhjal"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logija puhvri suurused"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Vali logija suur. logipuhvri kohta"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 2c81f2ef5ace..ca8ea039919e 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Sareak"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Hari gabeko bistaratze-egiaztatzea"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Gaitu Wi-Fi sareetan saioa hasteko modu xehatua"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Behartu Wi-Fi konexiotik datuenera aldatzera"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Onartu beti ibiltaritzan Wi-Fi sareak bilatzea"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Datu mugikorrak beti aktibo"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Konexioa partekatzeko hardwarearen azelerazioa"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Idatzi DNS hornitzailearen ostalari-izena"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago Wi-Fi sareetan saioa hasterakoan. Erakutsi sarearen identifikatzailea eta seinalearen indarra Wi‑Fi sareen hautagailuan."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Aukera hori gaituz gero, gailua nahitaez aldatuko da datu mugikorren konexiora Wi-Fi seinalea ahultzen dela nabaritutakoan"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Onartu edo debekatu ibiltaritzan Wi-Fi sareak bilatzea, interfazeko datu-trafikoaren arabera"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Erregistroen buffer-tamainak"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Hautatu erregistroen buffer-tamainak"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 4f3c77f7e9da..675e3827731b 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"شبکه"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"گواهینامه نمایش بیسیم"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"فعال کردن گزارشگیری طولانی Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi قوی برای واگذاری به دستگاه همراه"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"اسکنهای رومینگ Wi‑Fi همیشه مجاز است"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"داده تلفن همراه همیشه فعال باشد"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"شتاب سختافزاری اتصال به اینترنت با تلفن همراه"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"نام میزبان ارائهدهنده DNS خصوصی را وارد کنید"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"زمانیکه فعال است، درشرایطی که سیگنال Wi-Fi ضعیف باشد، Wi‑Fi برای واگذاری اتصال داده به دستگاه همراه قویتر عمل خواهد کرد."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"مجاز/غیرمجاز کردن اسکنهای رومینگ Wi‑Fi براساس مقدار ترافیک داده موجود در واسط"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"اندازههای حافظه موقت ثبتکننده"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"انتخاب اندازه ثبتکننده در حافظه موقت ثبت"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 5932d00afb0f..ba7fcd39ca3a 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Yhteysominaisuudet"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Langattoman näytön sertifiointi"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Käytä Wi-Fin laajennettua lokikirjausta"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Vaihda herkästi Wi-Fi mobiiliyhteyteen"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Salli Wi-Fi-verkkovierailuskannaus aina"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiilidata aina käytössä"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Laitteistokiihdytyksen yhteyden jakaminen"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Anna isäntänimi tai DNS-tarjoaja."</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kun asetus on käytössä, datayhteys siirtyy helpommin Wi-Fistä matkapuhelinverkkoon, jos Wi-Fi-signaali on heikko."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Salli/estä Wi-Fi-verkkovierailuskannaus liittymässä esiintyvän dataliikenteen perusteella."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Lokipuskurien koot"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Valitse puskurikohtaiset lokikoot"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index c0c29d3236fd..f266e2ddb725 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Réseautage"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certification de l\'affichage sans fil"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Autoriser enreg. données Wi-Fi détaillées"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Passage forcé du Wi-Fi aux données cell."</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Données cellulaires toujours actives"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Entrez le nom d\'hôte du fournisseur DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification d\'affichage sans fil"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si cette option est activée, le passage du Wi-Fi aux données cellulaires est forcé lorsque le signal Wi-Fi est faible"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Autoriser ou non la détection de réseaux Wi-Fi en itinérance en fonction de l\'importance du transfert de données dans l\'interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tailles des mémoires tampons d\'enregistreur"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Tailles enreg. par tampon journal"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 50c99e2a558e..87f00d151e18 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Mise en réseau"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certification affichage sans fil"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Autoriser enreg. infos Wi-Fi détaillées"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Passage forcé Wi-Fi vers données mobiles"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Données mobiles toujours actives"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Saisissez le nom d\'hôte du fournisseur DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si cette option est activée, le passage du Wi-Fi aux données mobiles est forcé en cas de signal Wi-Fi faible."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Autoriser ou non la détection de réseaux Wi-Fi en itinérance en fonction de l\'importance du trafic de données dans l\'interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tailles mémoires tampons enregistr."</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Tailles enreg. par tampon journal"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 775bbf1a9bbd..9026aaba9f68 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificado de visualización sen fíos"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Activar rexistro detallado da wifi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferencia agresiva de wifi a móbil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre buscas de itinerancia da wifi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móbiles sempre activados"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware para conexión compartida"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce o nome de host de provedor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nivel de rexistro da wifi, mostrar por SSID RSSI no selector de wifi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Cando estea activada esta función, a wifi será máis agresiva ao transferir a conexión de datos ao móbil cando o sinal wifi sexa feble"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/Non permitir buscas de itinerancia da wifi baseadas na cantidade de tráfico de datos presente na interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de rexistrador"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Seleccionar tamaños por búfer"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 712e57eb09da..b1ee90b2c6b0 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"નેટવર્કિંગ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"વાયરલેસ ડિસ્પ્લે પ્રમાણન"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"વાઇ-ફાઇ વર્બોઝ લૉગિંગ સક્ષમ કરો"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"સશક્ત Wi‑Fiથી મોબાઇલ પર હૅન્ડઓવર"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"હંમેશા વાઇ-ફાઇ રોમ સ્કૅન્સને મંજૂરી આપો"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"મોબાઇલ ડેટા હંમેશાં સક્રિય"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS પ્રદાતાના હોસ્ટનું નામ દાખલ કરો"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"જ્યારે સક્ષમ કરેલ હોય, ત્યારે વાઇ-ફાઇ સિગ્નલ નબળું હોવા પર, વાઇ-ફાઇ વધુ ઝડપથી ડેટા કનેક્શનને મોબાઇલ પર મોકલશે"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ઇન્ટરફેસ પર હાજર ડેટા ટ્રાફિકના પ્રમાણનાં આધારે વાઇ-ફાઇ રોમ સ્કૅન્સને મંજૂરી આપો/નામંજૂર કરો"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"લોગર બફર કદ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"લૉગ દીઠ લૉગર કદ બફર પસંદ કરો"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index a88abb5a7fa8..e235fc5b7741 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"नेटवर्किंग"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"वायरलेस दिखाई देने के लिए प्रमाणन"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"वाई-फ़ाई वर्बोस लॉगिंग चालू करें"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"वाई-फ़ाई से मोबाइल पर ज़्यादा तेज़ी से हैंडओवर"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"हमेशा वाई-फ़ाई रोम स्कैन करने दें"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा हमेशा सक्रिय"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS सेवा देने वाले का होस्टनाम डालें"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस दिखाई देने के लिए प्रमाणन विकल्प दिखाएं"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाई-फ़ाई प्रवेश स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"इसके सक्षम होने पर, जब वाई-फ़ाई संकेत कमज़ोर हों तो वाई-फ़ाई, डेटा कनेक्शन को मोबाइल पर ज़्यादा तेज़ी से भेजेगा"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"इंटरफ़ेस पर वर्तमान में मौजूद डेटा ट्रैफ़िक के आधार पर वाई-फ़ाई रोम स्कैन करने देता/नहीं देता है"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"लॉगर बफ़र आकार"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"प्रति लॉग बफ़र लॉगर आकार चुनें"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index a417cc153f77..a8549872146f 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikacija bežičnog prikaza"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući opširnu prijavu na Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aktivni prijelaz s Wi‑Fi na mob. mrežu"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopusti slobodno traženje Wi-Fi mreže"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilni podaci uvijek aktivni"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje za modemsko povezivanje"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Unesite naziv hosta davatelja usluge DNS-a"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ako je omogućeno, Wi-Fi će aktivno prebacivati podatkovnu vezu mobilnoj mreži kada je Wi-Fi signal slab."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dopustite ili blokirajte slobodno traženje Wi-Fi mreža na temelju količine podatkovnog prometa na sučelju."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine međuspremnika zapisnika"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Odaberite veličinu međuspremnika zapisnika"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index b6f1460a7ba5..553ed88d779e 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Hálózatok"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Vezeték nélküli kijelző tanúsítványa"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Részletes Wi-Fi-naplózás engedélyezése"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresszív Wi‑Fi–mobilhálózat átadás"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi-roaming ellenőrzésének engedélyezése mindig"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"A mobilhálózati kapcsolat mindig aktív"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Internetmegosztás hardveres gyorsítása"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Adja meg a DNS-szolgáltató gazdagépnevét"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ha engedélyezi, a Wi-Fi agresszívebben fogja átadni az adatkapcsolatot a mobilhálózatnak gyenge Wi-Fi-jel esetén"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"A Wi-Fi-roaming ellenőrzésének engedélyezése vagy letiltása az interfészen jelen lévő adatforgalom mennyiségétől függően"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Naplózási puffer mérete"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Naplózási pufferméret kiválasztása"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 3ba3f453a361..dced49f50fa3 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Ցանց"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Անլար էկրանի վկայագրում"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Միացնել Wi‑Fi մանրամասն գրանցամատյանները"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi-Fi-ից կտրուկ անցում բջջային ինտերնետի"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Միշտ թույլատրել Wi‑Fi ռոումինգի որոնումը"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Բջջային ինտերնետը միշտ ակտիվ է"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Սարքակազմի արագացման միացում"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Մուտքագրեք DNS ծառայության մատակարարի խնամորդի անունը"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի հավաստագրման ընտրանքները"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Եթե այս գործառույթը միացված է, Wi-Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից բջջային ինտերնետի անցումը ավելի կտրուկ կկատարվի"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Թույլատրել/արգելել Wi‑Fi ռոումինգի որոնումը՝ կախված միջերեսում տվյալների երթևեկի ծավալից"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Տեղեկամատյանի պահնակի չափերը"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Ընտրեք տեղեկամատյանի չափը մեկ պահնակի համար"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 2bb9ae0f3e1f..5c067663970a 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Jaringan"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Sertifikasi layar nirkabel"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktifkan Pencatatan Log Panjang Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Pengalihan Wi-Fi Agresif ke seluler"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Selalu izinkan Pemindaian Roaming Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Data seluler selalu aktif"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Akselerasi hardware tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan hostname penyedia DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Jika diaktifkan, Wi-Fi akan menjadi lebih agresif dalam mengalihkan sambungan data ke seluler saat sinyal Wi-Fi lemah"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Izinkan/Larang Pemindaian Roaming Wi-Fi berdasarkan jumlah lalu lintas data yang ada di antarmuka"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Ukuran penyangga pencatat log"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Ukuran Pencatat Log per penyangga log"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 311227f35875..21b8b0ed2975 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Netkerfi"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Vottun þráðlausra skjáa"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Kveikja á ítarlegri skráningu Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Hröð skipti úr Wi‑Fi í farsímagögn"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Leyfa alltaf reikileit með Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Alltaf kveikt á farsímagögnum"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Vélbúnaðarhröðun fyrir tjóðrun"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Slá inn hýsilheiti DNS-veitu"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Þegar þetta er virkt mun Wi-Fi skipta hraðar yfir í farsímagagnatengingu þegar Wi-Fi-tenging er léleg"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Leyfa/banna reikileit með Wi-Fi á grunni þess hversu mikil gagnaumferð er fyrir hendi í viðmótinu"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Annálsritastærðir biðminna"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veldu annálsritastærðir á biðminni"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index b63232d7a6a6..7408b25f7d10 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Reti"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificazione display wireless"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Attiva registrazione dettagliata Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi aggressivo per passaggio a cellulare"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Consenti sempre scansioni roaming Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dati mobili sempre attivi"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering accelerazione hardware"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Inserisci il nome host del provider DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta il livello di registrazione Wi-Fi, mostrando il SSID RSSI nel selettore Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Con questa impostazione attivata, il Wi-Fi è più aggressivo nel passare la connessione dati al cellulare, con segnale Wi-Fi basso"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Consenti/vieta scansioni roaming Wi-Fi basate sulla quantità di traffico dati presente a livello di interfaccia"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Dimensioni buffer Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Seleziona dimensioni Logger per buffer log"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 538da919c798..fceaacc0b7b6 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"תקשורת רשתות"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"אישור של תצוגת WiFi"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"הפעל רישום מפורט של Wi‑Fi ביומן"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"העברה אגרסיבית מ-Wi‑Fi לרשת סלולרית"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"התר תמיד סריקות נדידה של Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"חבילת הגלישה פעילה תמיד"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"צריך להזין את שם המארח של ספק DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"כשאפשרות זו מופעלת, Wi-Fi יתנהג בצורה אגרסיבית יותר בעת העברת חיבור הנתונים לרשת הסלולרית כשאות ה-Wi-Fi חלש."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"התר/מנע סריקות נדידה של Wi-Fi בהתבסס על נפח תנועת הנתונים הקיימת בממשק"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"גדלי מאגר של יומן רישום"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"בחר גדלים של יוצר יומן לכל מאגר יומן"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index db1baa1188c0..671320bc9444 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ネットワーク"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ワイヤレスディスプレイ認証"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi-Fi詳細ログの有効化"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi-Fi を強制的にモバイル接続に切り替える"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fiローミングスキャンを常に許可する"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"モバイルデータを常に ON にする"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"テザリング時のハードウェア アクセラレーション"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS プロバイダのホスト名を入力"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ワイヤレスディスプレイ認証のオプションを表示"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fiログレベルを上げて、Wi-Fi選択ツールでSSID RSSIごとに表示します"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ON にすると、Wi-Fi の電波強度が弱い場合は強制的にモバイルデータ接続に切り替わるようになります"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"インターフェースのデータトラフィック量に基づいたWi-Fiローミングスキャンを許可するかしないかを設定できます"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ログバッファのサイズ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"各ログバッファのログサイズを選択"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 00eaf84733d4..1948460ff731 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ქსელი"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"უსადენო ეკრანის სერტიფიცირება"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi-ს დაწვრილებითი აღრიცხვის ჩართვა"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi-ს მობ. ინტერნეტზე აგრესიული გადართვა"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Roam სკანირების მუდამ დაშვება"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"მობილური ინტერნეტის ყოველთვის გააქტიურება"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ტეტერინგის აპარატურული აჩქარება"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"შეიყვანეთ DNS პროვაიდერის სერვერის სახელი"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ჩართვის შემთხვევაში, Wi‑Fi უფრო აქტიურად შეეცდება მობილურ ინტერნეტზე გადართვას, როცა Wi‑Fi სიგნალი სუსტია"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Wifi Roam სკანირების დაშვება/აკრძალვა, ინტერფეისზე არსებული მონაცემთა ტრაფიკზე დაფუძნებით"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ჟურნალიზაციის ბუფერის ზომები"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"აირჩიეთ ჟურნ. ზომა / ჟურნ. ბუფერზე"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index a318bd88a8f0..2d03f7f82bc8 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Желі орнату"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Сымсыз дисплей сертификаты"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi егжей-тегжейлі журналға тір. қосу"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi-Fi желісінен мобильдік желіге ауысу"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобильдік деректер әрқашан қосулы"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингтің аппараттық жеделдетуі"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS провайдерінің хост атауын енгізіңіз"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi жур. тір. дең. арт., Wi‑Fi желісін таңдағышта әр SSID RSSI бойынша көрсету"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Wi‑Fi сигналы әлсіз болғанда, деректер байланысы мәжбүрлі түрде мобильдік желіге ауысады"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Интерфейсте бар деректер трафигінің мөлшерінің негізінде Wi-Fi роумингін іздеулерге рұқсат ету/тыйым салу"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Журналға тіркеуші буферінің өлшемдері"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Әр журнал буфері үшін журналға тіркеуші өлшемдерін таңдау"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index ae473187219b..1d2476cf6ca8 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ការភ្ជាប់បណ្ដាញ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"បង្ហាញការកំណត់រចនាសម្ព័ន្ធឥតខ្សែ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"បើកកំណត់ហេតុរៀបរាប់វ៉ាយហ្វាយ"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ប្តូរទៅប្រើបណ្តាញចល័តពេល Wi‑Fi មានរលកសញ្ញាខ្លាំងពេក"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"តែងតែអនុញ្ញាតការវិភាគរ៉ូមវ៉ាយហ្វាយ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ទិន្នន័យទូរសព្ទចល័តដំណើរការជានិច្ច"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ការបង្កើនល្បឿនផ្នែករឹងសម្រាប់ការភ្ជាប់"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"បញ្ចូលឈ្មោះម៉ាស៊ីនរបស់ក្រុមហ៊ុនផ្ដល់សេវា DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញជម្រើសសម្រាប់វិញ្ញាបនបត្របង្ហាញឥតខ្សែ"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"បង្កើនកម្រិតកំណត់ហេតុវ៉ាយហ្វាយបង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសវ៉ាយហ្វាយ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"នៅពេលដែលបើក នោះ Wi‑Fi នឹងផ្តល់ការតភ្ជាប់ទិន្នន័យយ៉ាងគំហុកទៅបណ្តាញទូរសព្ទចល័ត នៅពេលរលកសញ្ញា Wi‑Fi ចុះខ្សោយ។"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"អនុញ្ញាត/មិនអនុញ្ញាតការវិភាគរ៉ូមវ៉ាយហ្វាយផ្អែកលើចំនួនការបង្ហាញចរាចរណ៍ទិន្នន័យនៅចំណុចប្រទាក់"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ទំហំ buffer របស់ Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ជ្រើសទំហំ Logger per log buffer"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index fbabb627ce4d..385308aafab3 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ನೆಟ್ವರ್ಕಿಂಗ್"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi ವೆರ್ಬೋಸ್ ಲಾಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ವೈ-ಫೈನಿಂದ ಮೊಬೈಲ್ಗೆ ಆಕ್ರಮಣಕಾರಿ ಹಸ್ತಾಂತರ"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ವೈ-ಫೈ ರೋಮ್ ಸ್ಕ್ಯಾನ್ಗಳನ್ನು ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ಮೊಬೈಲ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ಹಾರ್ಡ್ವೇರ್ನ ವೇಗವರ್ಧನೆಯನ್ನು ಟೆಥರಿಂಗ್ ಮಾಡಿ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ಪೂರೈಕೆದಾರರ ಹೋಸ್ಟ್ಹೆಸರನ್ನು ನಮೂದಿಸಿ"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ಇದು ಸಕ್ರಿಯಗೊಂಡರೆ, ವೈ-ಫೈ ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದ್ದಾಗ, ಮೊಬೈಲ್ಗೆ ಡೇಟಾ ಸಂಪರ್ಕವನ್ನು ಹಸ್ತಾಂತರಿಸುವಲ್ಲಿ ವೈ-ಫೈ ಹೆಚ್ಚು ಆಕ್ರಮಣಕಾರಿಯಾಗಿರುತ್ತದೆ"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ಇಂಟರ್ಫೇಸ್ನಲ್ಲಿ ಲಭ್ಯವಿರುವ ಡೇಟಾ ಟ್ರಾಫಿಕ್ ಆಧಾರದ ಮೇಲೆ Wi‑Fi ರೋಮ್ ಸ್ಕ್ಯಾನ್ಗಳನ್ನು ಅನುಮತಿಸಿ/ನಿರಾಕರಿಸಿ"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ಲಾಗರ್ ಬಫರ್ ಗಾತ್ರಗಳು"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ ಲಾಗರ್ ಗಾತ್ರಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 4b7d0a4cd680..e1be8dc01d83 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"네트워크"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"무선 디스플레이 인증서"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi-Fi 상세 로깅 사용"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"적극적인 Wi-Fi-모바일 핸드오버"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi 로밍 스캔 항상 허용"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"항상 모바일 데이터 활성화"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"테더링 하드웨어 가속"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS 제공업체의 호스트 이름 입력"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시합니다."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"사용 설정하면 Wi-Fi 신호가 약할 때 데이터 연결을 Wi-Fi에서 모바일 네트워크로 더욱 적극적으로 핸드오버합니다."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"인터페이스에 표시되는 데이터 트래픽의 양을 기반으로 Wi-Fi 로밍 스캔을 허용하거나 허용하지 않습니다."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"로거 버퍼 크기"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"로그 버퍼당 로거 크기 선택"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 98ca36a6a2d2..d323df2e8405 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Тармактык байланыштарды кеңейтүү"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Зымсыз дисплейди аныктоо"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi дайын-даректүү протоколун иштетүү"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi начар болсо, мобилдик Инт-ке өтсүн"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi Роуминг Скандоо мүмкүнчүлүгүнө ар дайым уруксат берилсин"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилдик Интернет иштей берсин"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингдин иштешин тездетүү"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS түйүндүн аталышын киргизиңиз"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi Кармагычта Wi‑Fi протокол деңгээлин жогорулатуу жана ар бир SSID RSSI үчүн көрсөтүү."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Иштетилсе, Wi-Fi байланышы үзүл-кесил болуп жатканда, Wi-Fi тармагы туташууну мобилдик Интернетке өжөрлүк менен өткөрүп берет"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Интерфейстеги дайындар трафигинин көлөмүнө жараша Wi-Fi Роуминг скандоо мүмкүнчүлүгүн иштетүү/өчүрүү"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Каттагыч буферлеринин өлчөмдөрү"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Каттоо буфери үчүн Каттагычтын көлөмүн тандаңыз"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 6de2a2e95f75..1e58af1c7cd0 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ການສ້າງເຄືອຂ່າຍ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ສະແດງການຮັບຮອງຂອງລະບົບໄຮ້ສາຍ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"ເປີດນຳໃຊ້ການເກັບປະຫວັດ Verbose Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ສະຫຼັບເປັນ Wi-Fi ເມື່ອມືຖືສັນຍານອ່ອນ"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ອະນຸຍາດການສະແກນການໂຣມ Wi‑Fi ສະເໝີ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືຕະຫຼອດເວລາ"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ລະບຸຊື່ໂຮສຂອງຜູ້ໃຫ້ບໍລິການ DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ເມື່ອເປີດໃຊ້ແລ້ວ, Wi-Fi ຈະສົ່ງຜ່ານການເຊື່ອມຕໍ່ຂໍ້ມູນໄປຫາເຄືອຂ່າຍມືຖືເມື່ອສັນຍານ Wi-Fi ອ່ອນ"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ອະນຸຍາດ/ບໍ່ອະນຸຍາດການສະແກນການໂຣມ Wi-Fi ອີງຕາມຈຳນວນຂໍ້ມູນທີ່ເກີດຂຶ້ນໃນລະດັບສ່ວນຕິດຕໍ່"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ຂະໜາດບັບເຟີໂຕລັອກ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ເລືອກຂະໜາດລັອກຕໍ່ບັບເຟີ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 66fa62a89723..a35cd3c7be50 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Tinklai"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Belaidžio rodymo sertifikavimas"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Įgal. „Wi‑Fi“ daugiaž. įraš. į žurnalą"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agres. „Wi‑Fi“ perd. į mob. r. tinklą"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Visada leisti „Wi-Fi“ tarptiklinio ryšio nuskaitymą"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiliojo ryšio duomenys visada suaktyvinti"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Įveskite DNS teikėjo prieglobos serverio pavadinimą"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Jei ši parinktis įgalinta, „Wi‑Fi“ agresyviau perduos duomenų ryšiu į mobiliojo ryšio tinklą, kai „Wi‑Fi“ signalas silpnas"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Leisti / neleisti „Wi‑Fi“ tarptinklinio ryšio nuskaitymo, atsižvelgiant į sąsajos duomenų srauto kiekį"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Registruotuvo buferio dydžiai"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Pasir. registr. dydž. žurn. bufer."</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index f32accddfc99..8239d9f62042 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Tīklošana"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Bezvadu attēlošanas sertifikācija"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Iespējot Wi‑Fi detalizēto reģistrēšanu"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresīva pāreja no Wi‑Fi uz mobilo tīklu"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vienmēr atļaut Wi‑Fi meklēšanu"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Vienmēr aktīvs mobilo datu savienojums"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Paātrināta aparatūras darbība piesaistei"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ievadiet DNS pakalpojumu sniedzēja saimniekdatora nosaukumu"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ja opcija ir iespējota un Wi‑Fi signāls ir vājš, datu savienojuma pāreja no Wi-Fi uz mobilo tīklu tiks veikta agresīvāk."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Atļaujiet/neatļaujiet Wi‑Fi meklēšanu, pamatojoties uz saskarnē saņemto datplūsmas apjomu."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Reģistrētāja buferu lielumi"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Atlasīt reģistrētāja bufera liel."</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 3151f5677008..eaa553903a32 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Вмрежување"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Приказ на сертификација на безжична мрежа"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Овозможи преопширно пријавување Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Агресивно предавање од Wi‑Fi на мобилен"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Секогаш дозволувај Wi‑Fi скенирање во роаминг"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилниот интернет е секогаш активен"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско забрзување за врзување"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Внесете име на хост на операторот на DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Кога е овозможено, Wi-Fi ќе биде поагресивна при предавање на интернет-врската на мобилната мрежа при слаб сигнал на Wi-Fi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Дозволи/Забрани Wi‑Fi скенирање во роаминг според количината на постоечкиот податочен сообраќај на интерфејсот."</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Величини на меѓумеморија на забележувач"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Величина/меѓумеморија на дневник"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 2b86e509fb05..0ddfc793312e 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"നെറ്റ്വര്ക്കിംഗ്"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷൻ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"വൈഫൈ വെർബോസ് ലോഗിംഗ് പ്രവർത്തനക്ഷമമാക്കുക"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"മൊബൈൽ ഹാൻഡ്ഓവറിലേക്ക് വൈഫൈ സക്രിയമാക്കുക"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"എപ്പോഴും വൈഫൈ റോം സ്കാൻ അനുവദിക്കൂ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"മൊബൈൽ ഡാറ്റ എല്ലായ്പ്പോഴും സജീവം"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ടെതറിംഗ് ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തൽ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ദാതാവിന്റെ ഹോസ്റ്റുനാമം നൽകുക"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"പ്രവർത്തനക്ഷമമായിരിക്കുമ്പോൾ, വൈഫൈ സിഗ്നൽ കുറവായിരിക്കുന്ന സമയത്ത് മൊബൈലിലേക്ക് ഡാറ്റ കണക്ഷൻ വഴി കൈമാറുന്നതിൽ വൈഫൈ കൂടുതൽ സക്രിയമായിരിക്കും"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ഇന്റർഫേസിലെ ഡാറ്റ ട്രാഫിക്ക് സാന്നിദ്ധ്യത്തിന്റെ കണക്ക് അടിസ്ഥാനമാക്കി വൈഫൈ റോം സ്കാനുകൾ അനുവദിക്കുക/അനുവദിക്കാതിരിക്കുക"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ലോഗർ ബഫർ വലുപ്പം"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ഓരോ ലോഗ് ബഫറിനും വലുപ്പം തിരഞ്ഞെടുക്കൂ"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 152408aa6213..67c64958fed1 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Сүлжээ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Утасгүй дэлгэцийн сертификат"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi Verbose лог-г идэвхжүүлэх"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Идэвхтэй Wi‑Fi-с мобайл сүлжээнд"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Роум сканыг байнга зөвшөөрөх"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобайл дата байнга идэвхтэй"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Модем болгох хардвер хурдасгуур"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS-н үйлчилгээ үзүүлэгчийн хостын нэрийг оруулах"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Идэвхжүүлсэн үед Wi‑Fi холболт сул байх үед дата холболтыг мобайлд шилжүүлэхэд илүү идэвхтэй байх болно"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Интерфэйс дээрх дата трафикын хэмжээнээс хамааран Wi‑Fi Роум Скан-г зөвшөөрөх/үл зөвшөөрөх"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Логгерын буферын хэмжээ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Лог буфер бүрт ногдох логгерын хэмжээг сонгоно уу"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 7402d29ee2e9..eeb0a165cf37 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"नेटवर्किंग"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"वायरलेस डिस्प्ले प्रमाणीकरण"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"वाय-फाय व्हर्बोझ लॉगिंग सक्षम करा"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"मोबाइलकडे सोपवण्यासाठी अॅग्रेसिव्ह वाय-फाय"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाय-फाय रोम स्कॅनला नेहमी अनुमती द्या"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा नेहमी सक्रिय"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिंग हार्डवेअर प्रवेग"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS पुरवठादाराचे होस्टनाव टाका"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय सिलेक्टरमध्ये प्रति SSID RSSI दर्शवा"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"सक्षम केले असताना, वाय-फाय सिग्नल कमी असताना, मोबाइलकडे डेटा कनेक्शन सोपवण्यासाठी वाय-फाय अधिक अॅग्रेसिव्ह असेल."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"वाय-फाय रोम स्कॅनला इंटरफेसवर उपस्थित असलेल्या रहदारी डेटाच्या प्रमाणावर आधारित अनुमती द्या/अनुमती देऊ नका"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"लॉगर बफर आकार"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"प्रति लॉग बफर लॉगर आकार निवडा"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 51ab84e05de6..a69024c50d05 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Perangkaian"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Pensijilan paparan wayarles"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Dayakan Pengelogan Berjela-jela Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Penyerahan Wi-Fi ke mudah alih agresif"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sentiasa benarkan Imbasan Perayauan Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Data mudah alih sentiasa aktif"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Pecutan perkakasan penambatan"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Masukkan nama hos pembekal DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Apabila didayakan, Wi-Fi akan menjadi lebih agresif dalam menyerahkan sambungan data ke mudah alih, apabila isyarat Wi-Fi rendah"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Benarkan/Jangan benarkan Imbasan Perayauan Wi-Fi berdasarkan jumlah trafik data yang ada pada antara muka"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Saiz penimbal pengelog"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Pilih saiz Pengelog bagi setiap penimbal log"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index c643c595a6ef..5e78249ca172 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ချိတ်ဆက်ဆောင်ရွက်ခြင်း"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ကြိုးမဲ့ပြသမှု အသိအမှတ်ပြုလက်မှတ်"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi Verbose မှတ်တမ်းတင်ခြင်းအား ဖွင့်မည်"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi မှ မိုဘိုင်းသို့ လွှဲပြောင်းရန်"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi ရွမ်းရှာဖွေမှုကို အမြဲတမ်း ခွင့်ပြုမည်"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"မိုဘိုင်းဒေတာကို အမြဲဖွင့်ထားရန်"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ဝန်ဆောင်မှုပေးသူ၏ အင်တာနက်လက်ခံဝန်ဆောင်ပေးသူအမည်ကို ထည့်ပါ"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ဖွင့်ထားပါက Wi‑Fi လွှင့်အား နည်းချိန်တွင် Wi‑Fi မှ မိုဘိုင်းသို့ ဒေတာချိတ်ဆက်မှုကို လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"မျက်နှာပြင်တွင် ဖော်ပြသည့် အချက်လက် အသွားအလာ ပမာဏပေါ်တွင် အခြေခံ၍ WIFI ရွမ်းရှာဖွေမှုအား ဖွင့်/ပိတ်မည်"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"လော့ဂါး ဘာဖား ဆိုက်များ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"လော့ ဘာဖားတွက် လော့ဂါးဆိုက် ရွေး"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 0cea1a78e503..d45bbc3bbe80 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Nettverk"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Trådløs skjermsertifisering"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktiver detaljert Wi-Fi-loggføring"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressiv overføring fra Wi-Fi til mobil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillat alltid skanning for Wi-Fi-roaming"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata er alltid aktiv"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvareakselerasjon for internettdeling"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Skriv inn vertsnavnet til DNS-leverandøren"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Hvis dette slås på, overfører Wi-Fi-nettverket datatilkoblingen til mobil mer aggressivt når Wi-Fi-signalet er svakt"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Tillat / ikke tillat skanning for Wi-Fi-roaming basert på mengden datatrafikk til stede i grensesnittet"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Bufferstørrelser for logg"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Velg loggstørrelse per loggbuffer"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index d0ec0f5ee01d..d26541ca167e 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"नेटवर्किङ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ताररहित प्रदर्शन प्रमाणीकरण"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi-Fi वर्बोज लग सक्षम पार्नुहोस्"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"आक्रामक ढंगले Wi‑Fi बाट मोबाइलमा हस्तान्तरण"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi घुम्ने स्क्यान गर्न सधैँ अनुमति दिनुहोस्"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा सधैँ सक्रिय राख्नुहोस्"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्ट गर्नुहोस्"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"सक्षम गरिएको अवस्थामा, Wi-Fi सिग्नल न्यून हुँदा, Wi-Fi ले बढी आक्रामक ढंगले मोबाइलमा डेटा जडान हस्तान्तरण गर्नेछ"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Wi-Fi घुम्ने स्क्यान इन्टरफेसमा रहेको डेटा यातायातको मात्रामा आधारित अनुमति दिनुहोस्/नदिनुहोस्"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"लगर बफर आकारहरू"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"लग बफर प्रति लगर आकार चयन गर्नुहोस्"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 87d20c2e4ae3..ce25cc74fae7 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Netwerken"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificering van draadloze weergave"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Uitgebreide wifi-logregistratie insch."</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agressieve handover van wifi naar mobiel"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiele data altijd actief"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareversnelling voor tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Geef hostnaam van DNS-provider op"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Indien ingeschakeld, is wifi agressiever bij het overgeven van de gegevensverbinding aan mobiel wanneer het wifi-signaal zwak is"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Roamingscans voor wifi (niet) toestaan op basis van de hoeveelheid dataverkeer die aanwezig is bij de interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Logger-buffergrootten"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Kies Logger-grootten per logbuffer"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index d870a99d9647..d64c30f4246c 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ਨੈੱਟਵਰਕਿੰਗ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"ਵਾਈ-ਫਾਈ ਵਰਬੋਸ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ਆਕਰਮਣਸ਼ੀਲ ਵਾਈ‑ਫਾਈ ਤੋਂ ਮੋਬਾਈਲ ਹੈਂਡਓਵਰ"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ਹਮੇਸ਼ਾਂ ਵਾਈ‑ਫਾਈ ਰੋਮ ਸਕੈਨਾਂ ਦੀ ਆਗਿਆ ਦਿਓ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ਪ੍ਰਦਾਨਕ ਦਾ ਹੋਸਟਨਾਮ ਦਾਖਲ ਕਰੋ"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ਜਦੋਂ ਯੋਗ ਬਣਾਇਆ ਹੋਵੇ, ਤਾਂ ਵਾਈ‑ਫਾਈ ਸਿਗਨਲ ਘੱਟ ਹੋਣ \'ਤੇ ਵਾਈ‑ਫਾਈ ਡਾਟਾ ਕਨੈਕਸ਼ਨ ਮੋਬਾਈਲ ਨੂੰ ਹੈਂਡ ਓਵਰ ਕਰਨ ਵਿੱਚ ਵੱਧ ਆਕਰਮਣਸ਼ੀਲ ਹੋਵੇਗਾ।"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ਇੰਟਰਫੇਸ ਤੇ ਮੌਜੂਦ ਡਾਟਾ ਟ੍ਰੈਫਿਕ ਦੀ ਮਾਤਰਾ ਦੇ ਆਧਾਰ ਤੇ ਵਾਈ-ਫਾਈ ਰੋਮ ਸਕੈਨ ਦੀ ਆਗਿਆ ਦਿਓ/ਅਸਵੀਕਾਰ ਕਰੋ"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ਲੌਗਰ ਬਫ਼ਰ ਆਕਾਰ"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ ਲੌਗਰ ਆਕਾਰ ਚੁਣੋ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 7b66aa53bfbe..d50528dae95d 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Sieci"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Wyświetlacz bezprzewodowy"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Szczegółowy dziennik Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Przełączaj z Wi-Fi na sieć komórkową"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Zawsze szukaj Wi-Fi w roamingu"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna transmisja danych zawsze aktywna"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Akceleracja sprzętowa tetheringu"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Wpisz nazwę hosta dostawcy DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Po włączeniu połączenie danych będzie bardziej agresywnie przełączać się z Wi-Fi na sieć komórkową przy słabym sygnale Wi-Fi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Zezwalaj/nie zezwalaj na wyszukiwanie sieci Wi-Fi w roamingu w zależności od natężenia ruchu"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Rozmiary bufora Rejestratora"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Wybierz rozmiary Rejestratora/bufor dziennika"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index d99097a9b82f..67fda0390e50 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificação de Display sem fio"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro extenso de Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Mudança agressiva de Wi-Fi para móvel"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quando ativada, o Wi-Fi será mais agressivo em passar a conexão de dados para móvel, quando o sinal de Wi-Fi estiver fraco"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/proibir verificações de roaming de Wi-Fi com base no volume do tráfego de dados presente na interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de log"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 8c7fbba34e12..d7496454c471 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificação de display sem fios"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar o registo verboso de Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Mudança brusca de Wi‑Fi para rede móvel"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre a deteção de Wi-Fi em roaming"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduza o nome de anfitrião do fornecedor DNS."</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Se estiver ativado, o Wi-Fi será mais agressivo ao transmitir a lig. de dados para a rede móvel quando o sinal Wi-Fi estiver fraco"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/impedir a deteção de Wi-Fi em roaming com base na quantidade de tráfego de dados presente na interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos da memória intermédia do registo"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Selec. tam. reg. p/ mem. int. reg."</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index d99097a9b82f..67fda0390e50 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Redes"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificação de Display sem fio"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Ativar registro extenso de Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Mudança agressiva de Wi-Fi para móvel"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Informe o nome do host do provedor de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quando ativada, o Wi-Fi será mais agressivo em passar a conexão de dados para móvel, quando o sinal de Wi-Fi estiver fraco"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permitir/proibir verificações de roaming de Wi-Fi com base no volume do tráfego de dados presente na interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de log"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 1c6755077feb..1e91d8264f07 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Conectare la rețele"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certificare Ecran wireless"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Înregistrare prin Wi-Fi de volume mari de date"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Predare agresivă de la Wi-Fi la mobilă"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Se permite întotdeauna scanarea traficului Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Date mobile permanent active"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Accelerare hardware pentru tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduceți numele de gazdă al furnizorului de DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Când este activată, Wi-Fi va fi mai agresivă la predarea conexiunii de date către rețeaua mobilă când semnalul Wi-Fi este slab"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Permiteți/Nu permiteți scanarea traficului Wi-Fi în funcție de traficul de date din interfață"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Dimensiunile tamponului jurnalului"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Dimensiuni jurnal / tampon jurnal"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 4b1159441e97..693332f52e8f 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Сети"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Серт. беспроводн. мониторов"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Подробный журнал Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Переключаться на мобильную сеть"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Всегда включать поиск сетей Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Не отключать мобильный Интернет"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Аппаратное ускорение в режиме модема"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введите имя хоста поставщика услуг DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"При выборе Wi‑Fi указывать в журнале RSSI для каждого SSID"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Принудительно переключаться на мобильную сеть, если сигнал Wi-Fi слабый"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Включать или отключать поиск сетей Wi-Fi во время передачи данных в зависимости от объема трафика"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Размер буфера журнала"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Выберите размер буфера журнала"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 2ffe814dd476..6abd14da6f26 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"ජාලකරණය"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"නොරැහැන් සංදර්ශක සහතිකය"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"විස්තරාත්මක Wi‑Fi ලොග් කිරීම සබල කරන්න"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ආක්රමණික Wi‑Fi සිට ජංගම බාර දීම"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi රෝම් පරිලෝකන වෙතට සැමවිට අවසර දෙන්න"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"ජංගම දත්ත සැමවිට ක්රියාකාරීය"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ටෙදරින් දෘඪාංග ත්වරණය"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS සැපයුම්කරුගේ සත්කාරක නම ඇතුළු කරන්න"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"සබල විට Wi‑Fi සිග්නලය අඩු විට Wi‑Fi දත්ත සම්බන්ධතාවය ජංගම වෙත භාර දීමට වඩා ආක්රමණික වේ"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"අතුරු මුහුණතෙහි ඇති දත්ත තදබදය අනුව Wi‑Fi රෝම් පරිලෝකන වෙත ඉඩ දෙන්න/නොදෙන්න"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ලෝගයේ අන්තරාවක ප්රමාණය"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"ලොග අන්තරාවකට ලෝගයේ ප්රමාණය තෝරන්න"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 0cefd71832c4..8cc2dac2d304 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Siete"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikácia bezdrôtového zobrazenia"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Podrobné denníky Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agres. odovzdávať Wi‑Fi na mobilnú sieť"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povoliť funkciu Wi‑Fi Roam Scans"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilné dáta ponechať vždy aktívne"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardvérovú akcelerácia pre tethering"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Zadajte názov hostiteľa poskytovateľa DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Keď túto možnosť zapnete, Wi‑Fi bude agresívnejšie odovzdávať dátové pripojenie na mobilnú sieť vtedy, keď bude slabý signál Wi‑Fi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Povoliť alebo zakázať funkciu Wifi Roam Scans na základe objemu prenosu údajov v rozhraní"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Vyrovnávacia pamäť nástroja denníkov"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Veľkosť vyrovnávacej pamäte nástroja denníkov"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 0864d5b921f2..af8eb6e11d6f 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Omrežja"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Potrdilo brezžičnega zaslona"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogoči podrob. zapis. dnevnika za Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Odločen prehod iz Wi-Fi-ja v mobil. omr."</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vedno omogoči iskanje omrežij Wi-Fi za gostovanje"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Vnesite ime gostitelja pri ponudniku strežnika DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Če je ta možnost omogočena, Wi-Fi odločneje preda podatkovno povezavo mobilnemu omrežju, ko je signal Wi-Fi šibek."</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Omogoči/onemogoči iskanje omrežij Wi-Fi za gostovanje glede na količino podatkovnega prometa pri vmesniku"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Velikosti medpomn. zapisov. dnevnika"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Izberite velikost medpomnilnika dnevnika"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 63da6ffd2a63..88b1057739bc 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Rrjetet"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifikimi i ekranit valor"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktivizo hyrjen Wi-Fi Verbose"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Dorëzimi agresiv i Wi‑Fi te rrjeti celular"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Lejo gjithmonë skanimet për Wi-Fi edhe kur je në lëvizje"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Të dhënat celulare gjithmonë aktive"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Përshpejtimi i harduerit për ndarjen"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Fut emrin e pritësit të ofruesit të DNS-së"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kur ky funksion aktivizohet, Wi‑Fi bëhet më agresiv në kalimin e lidhjes së të dhënave te rrjeti celular, në rastet kur sinjali Wi‑Fi është i dobët"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Lejo/Ndalo skanimet për Wi‑Fi në roaming, bazuar në sasinë e trafikut të të dhënave të pranishme në ndërfaqe"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Madhësitë e regjistruesit"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Përzgjidh madhësitë e regjistruesit"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 4c7aed8e29a3..362fc1fb77dd 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Умрежавање"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Сертификација бежичног екрана"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Омогући детаљнију евиденцију за Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Агресиван прелаз са Wi‑Fi мреже на мобилну"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Увек дозволи скенирање Wi‑Fi-ја у ромингу"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилни подаци су увек активни"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско убрзање привезивања"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Унесите име хоста добављача услуге DNS-а"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Кад се омогући, Wi‑Fi ће бити агресивнији при пребацивању мреже за пренос података на мобилну ако је Wi‑Fi сигнал слаб"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Дозволи/забрани скенирање Wi-Fi-ја у ромингу на основу присутног протока података на интерфејсу"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Величине бафера података у програму за евидентирање"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Изаберите величине по баферу евиденције"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index e44dcd8dde6d..230dfeefdd8e 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Nätverk"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certifiering för Wi-Fi-skärmdelning"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Aktivera utförlig loggning för Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Aggressiv överlämning fr. Wi-Fi t. mobil"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillåt alltid sökning efter Wi-Fi-roaming"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata alltid aktiverad"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvaruacceleration för internetdelning"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ange värdnamn för DNS-leverantör"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"När funktionen har aktiverats kommer dataanslutningen lämnas över från Wi-Fi till mobilen på ett aggressivare sätt när Wi-Fi-signalen är svag"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Tillåt/tillåt inte sökning efter Wi-Fi-roaming utifrån mängden datatrafik i gränssnittet"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Buffertstorlekar för logg"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Välj loggstorlekar per loggbuffert"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 66cfda8b8079..1d462603750b 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Mtandao"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Chaguo za cheti cha kuonyesha pasiwaya"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Washa Uwekaji kumbukumbu za WiFi kutumia Sauti"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Ukabidhi hima kutoka Wifi kwenda mtandao wa simu"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Ruhusu Uchanganuzi wa Matumizi ya Mitandao mingine"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Iendelee kutumia data ya simu"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Weka jina la mpangishi wa huduma za DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ikiwashwa, Wi-Fi itakabidhi kwa hima muunganisho wa data kwa mtandao wa simu, wakati mtandao wa Wi-Fi si thabiti"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Ruhusu au Zuia Uchanganuzi wa Matumizi ya Mitandao mingine ya Wifi kulingana na kiasi cha trafiki ya data kilicho kwenye kiolesura"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Ukubwa wa kiweka bafa ya kumbukumbu"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Chagua ukubwa wa kila Kumbukumbu"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index dd218c61ab15..e9fd79bfe9a7 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"நெட்வொர்க்கிங்"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"வயர்லெஸ் காட்சிக்கான சான்றிதழ்"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"வைஃபை அதிவிவர நுழைவை இயக்கு"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ஒத்துழைக்காத வைஃபையிலிருந்து மொபைல் தரவிற்கு மாறு"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"எப்போதும் வைஃபை ரோமிங் ஸ்கேன்களை அனுமதி"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"மொபைல் டேட்டாவை எப்போதும் இயக்கத்திலேயே வை"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS வழங்குநரின் ஹோஸ்ட் பெயரை உள்ளிடவும்"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wifi நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"இயக்கப்பட்டதும், வைஃபை சிக்னல் குறையும் போது, வைஃபை முழுமையாக ஒத்துழைக்காமல் இருந்தால் மொபைல் தரவிற்கு மாறும்"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"இடைமுகத்தில் உள்ள ட்ராஃபிக் தரவின் அளவைப் பொறுத்து வைஃபை ரோமிங் ஸ்கேன்களை அனுமதி/அனுமதிக்காதே"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"லாகர் பஃபர் அளவுகள்"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"லாக் பஃபர் ஒன்றிற்கு லாகர் அளவுகளைத் தேர்வுசெய்க"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index b21eb8c8f8c0..c2b738ac9898 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"నెట్వర్కింగ్"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"వైర్లెస్ ప్రదర్శన ప్రమాణీకరణ"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi విశదీకృత లాగింగ్ను ప్రారంభించండి"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"మొబైల్కి మార్చేలా చురుకైన Wi‑Fi"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi సంచార స్కాన్లను ఎల్లప్పుడూ అనుమతించు"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"మొబైల్ డేటాని ఎల్లప్పుడూ సక్రియంగా ఉంచు"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"టెథెరింగ్ హార్డ్వేర్ వేగవృద్ధి"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS ప్రదాత యొక్క హోస్ట్పేరును నమోదు చేయండి"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"వైర్లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ప్రారంభించబడినప్పుడు, Wi‑Fi సిగ్నల్ బలహీనంగా ఉంటే డేటా కనెక్షన్ను మొబైల్కి మార్చేలా Wi‑Fi చురుగ్గా వ్యవహరిస్తుంది"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"ఇంటర్ఫేస్లో ఉండే డేటా ట్రాఫిక్ పరిమాణం ఆధారంగా Wi‑Fi సంచార స్కాన్లను అనుమతించు/నిరాకరించు"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"లాగర్ బఫర్ పరిమాణాలు"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"లాగ్ బఫర్కి లాగర్ పరిమా. ఎంచుకోండి"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 447b188a4b89..57b12a5601a7 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"เครือข่าย"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"การรับรองการแสดงผลแบบไร้สาย"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"เปิดใช้การบันทึกรายละเอียด Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"สลับ Wi‑Fi เป็นมือถือเมื่อสัญญาณอ่อน"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ใช้การสแกน Wi-Fi ข้ามเครือข่ายเสมอ"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"เปิดใช้อินเทอร์เน็ตมือถือเสมอ"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ป้อนชื่อโฮสต์ของผู้ให้บริการ DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"เมื่อเปิดใช้แล้ว Wi-Fi จะส่งผ่านการเชื่อมต่อข้อมูลไปยังเครือข่ายมือถือเมื่อสัญญาณ Wi-Fi อ่อน"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"อนุญาต/ไม่อนุญาตการสแกน Wi-Fi ข้ามเครือข่าย ตามปริมาณข้อมูลการเข้าชมที่ปรากฏในอินเทอร์เฟซ"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"ขนาดบัฟเฟอร์ของ Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"เลือกขนาด Logger ต่อบัฟเฟอร์ไฟล์บันทึก"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index a5e0b8960239..72261afd43ea 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Networking"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Certification ng wireless display"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"I-enable ang Pagla-log sa Wi‑Fi Verbose"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Agresibong paglipat ng Wi‑Fi sa mobile"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Palaging payagan ang Mga Pag-scan sa Roaming ng Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Palaging aktibo ang mobile data"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardware acceleration para sa pag-tether"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Ilagay ang hostname ng DNS provider"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Kapag na-enable, magiging mas agresibo ang Wi‑Fi sa paglipat sa koneksyon ng mobile data kapag mahina ang signal ng Wi‑Fi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Payagan/Huwag payagan ang Mga Pag-scan sa Roaming ng Wi‑Fi batay sa dami ng trapiko ng data na mayroon sa interface"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Mga laki ng buffer ng Logger"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Pumili ng mga laki ng Logger bawat log buffer"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index e6bba5be7a4a..948e4e5c9465 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Ağ işlemleri"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Kablosuz ekran sertifikası"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Kablosuz Ayrıntılı Günlük Kaydını etkinleştir"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Kablosuzdan mobil ağa agresif geçiş"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Kablosuz Dolaşım Taramalarına daima izin ver"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil veri her zaman etkin"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering donanım hızlandırıcısı"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS sağlayıcının ana makine adını gir"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Etkinleştirildiğinde, kablosuz ağ sinyali zayıfken veri bağlantısının mobil ağa geçirilmesinde daha agresif olunur"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Arayüzde mevcut veri trafiği miktarına bağlı olarak Kablosuz Dolaşım Taramalarına İzin Verin/Vermeyin"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Günlük Kaydedici arabellek boyutları"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Gün. arabel. başına Gün. Kayd. boyutunu seç"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 65f39edd1f5a..664fda7a2413 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Мережі"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Сертифікація бездрот. екрана"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Докладний запис у журнал Wi-Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Перемикатися з Wi-Fi на мобільну мережу"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Завжди шукати мережі Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Не вимикати мобільне передавання даних"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратне прискорення під час використання телефона в режимі модема"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Введіть ім’я хосту постачальника послуг DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Примусово перемикатися на мобільну мережу, коли сигнал Wi-Fi слабкий"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Дозволити чи заборонити Wi-Fi шукати роумінг на основі обсягу трафіку даних в інтерфейсі"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Розміри буфера журналу"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Виберіть розміри буфера журналу"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 7830bb86ce72..226b862fc6fb 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"نیٹ ورکنگ"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"وائرلیس ڈسپلے سرٹیفیکیشن"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi وربوس لاگنگ فعال کریں"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi‑Fi سے موبائل کو جارحانہ ہینڈ اوور"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"ٹیدرنگ ہارڈویئر سرعت کاری"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS فراہم کنندہ کے میزبان کا نام درج کریں"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"فعال کئے جانے پر، جب Wi‑Fi سگنل کمزور ہوگا، تو Wi‑Fi موبائل پر ڈیٹا کنکشن بھیجنے کیلئے مزید جارحانہ کارروائی کرے گا"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"انٹرفیس پر موجود ڈیٹا ٹریفک کی مقدار کی بنیاد پر Wi‑Fi روم اسکینز کی اجازت دیں/اجازت نہ دیں"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"لاگر بفر کے سائز"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"فی لاگ بفر لاگر کے سائز منتخب کریں"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index acaaaf1b8f5d..fdb3ef478467 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Tarmoqlar"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Simsiz monitor sertifikatlari"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Batafsil Wi-Fi jurnali"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Mobil internetga o‘tish"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi tarmoqlarini qidirishga doim ruxsat"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil internet doim yoniq tursin"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Modem rejimida apparatli tezlashtirish"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderining host nomini kiriting"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Agar ushbu funksiya yoqilsa, Wi-Fi signali past bo‘lganda internetga ulanish majburiy ravishda mobil internetga o‘tkaziladi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Ma’lumotlarni uzatish vaqtida trafik hajmiga qarab Wi-Fi tarmoqlarni qidirish funksiyasini yoqish yoki o‘chirish"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Jurnal buferi hajmi"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Jurnal xotirasi hajmini tanlang"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 7732b54c2c6d..a7a585583a84 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Mạng"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Chứng nhận hiển thị không dây"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Bật ghi nhật ký chi tiết Wi‑Fi"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Chuyển vùng Wi‑Fi tích cực sang mạng DĐ"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luôn cho phép quét chuyển vùng Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Dữ liệu di động luôn hiện hoạt"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tăng tốc phần cứng cho chia sẻ kết nối"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Nhập tên máy chủ của nhà cung cấp DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Khi được bật, Wi‑Fi sẽ tích cực hơn trong việc chuyển vùng kết nối dữ liệu sang mạng di động khi tín hiệu Wi‑Fi yếu"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Cho phép/Không cho phép quét chuyển vùng Wi‑Fi dựa trên lưu lượng truy cập dữ liệu có tại giao diện"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Kích cỡ tải trình ghi"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Chọn kích thước Trình ghi/lần tải nhật ký"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index f036eae1ff0c..5a1d0671cba6 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"网络"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"无线显示认证"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"启用WLAN详细日志记录功能"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"主动从 WLAN 网络切换到移动数据网络"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允许WLAN漫游扫描"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"始终开启移动数据网络"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"网络共享硬件加速"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"输入 DNS 提供商的主机名"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"显示无线显示认证选项"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"提升WLAN日志记录级别(在WLAN选择器中显示每个SSID的RSSI)"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"开启此设置后,系统会在 WLAN 信号较弱时,主动将网络模式从 WLAN 网络切换到移动数据网络"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"根据接口中目前的数据流量允许/禁止WLAN漫游扫描"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"日志记录器缓冲区大小"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"选择每个日志缓冲区的日志记录器大小"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index d57a8fd01196..acc3bb83226c 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"網絡"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"無線螢幕分享認證"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"啟用 Wi‑Fi 詳細記錄"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"加強 Wi-Fi 至流動數據轉換"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"永遠允許 Wi-Fi 漫遊掃描"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"一律保持啟用流動數據"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"網絡共享硬件加速"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"輸入網域名稱系統 (DNS) 供應商的主機名稱"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"啟用後,Wi-Fi 連線會在訊號不穩定的情況下更積極轉換成流動數據連線"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"根據介面中目前的數據流量允許/禁止 WiFi 漫遊掃描"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"記錄器緩衝區空間"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"選取每個記錄緩衝區的記錄器空間"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 5a329fa9c25f..775b92877628 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"網路連線"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"無線螢幕分享認證"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"啟用 Wi‑Fi 詳細紀錄設定"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Wi-Fi 至行動數據轉換強化"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允許 Wi-Fi 漫遊掃描"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"行動數據連線一律保持啟用狀態"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"數據連線硬體加速"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"輸入 DNS 供應商的主機名稱"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"啟用時,Wi-Fi 連線在訊號不穩的情況下會更積極轉換成行動數據連線"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"根據介面中目前的數據流量允許/禁止 Wi-Fi 漫遊掃描"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"紀錄器緩衝區空間"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"選取每個紀錄緩衝區的紀錄器空間"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 3649ba24ebd0..13b16037a549 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -196,7 +196,6 @@ <string name="debug_networking_category" msgid="7044075693643009662">"Ukunethiwekha"</string> <string name="wifi_display_certification" msgid="8611569543791307533">"Ukunikezwa isitifiketi sokubukeka okungenantambo"</string> <string name="wifi_verbose_logging" msgid="4203729756047242344">"Nika amandlaukungena kwe-Wi-Fi Verbose"</string> - <string name="wifi_aggressive_handover" msgid="5309131983693661320">"Ukudluliselwa okunamandla kakhulu kwe-Wi-Fi ukuya kuselula"</string> <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vumela njalo ukuskena kokuzula kwe-Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Idatha yeselula ihlala isebenza"</string> <string name="tethering_hardware_offload" msgid="7470077827090325814">"I-Tethering hardware acceleration"</string> @@ -223,7 +222,6 @@ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Faka igama lomsingathi womhlinzeki we-DNS"</string> <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string> <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string> - <string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Uma inikwe amandla, i-Wi-Fi izoba namandla kakhulu ekudluliseleni ukuxhumeka kwedatha kuselula, uma isignali ye-Wi-Fi iphansi"</string> <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Vumela/Ungavumeli ukuskena kokuzula kwe-Wi-Fi okususelwa kunani ledatha yethrafikhi ekhona ekusebenzisaneni"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Amasayizi weloga ngebhafa"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Khetha amasayizi weloga ngebhafa ngayinye yelogu"</string> diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml index bd963e96dcab..ddb49b6c3874 100644 --- a/packages/SettingsLib/res/values/dimens.xml +++ b/packages/SettingsLib/res/values/dimens.xml @@ -74,4 +74,13 @@ fraction of a pixel.--> <fraction name="battery_subpixel_smoothing_left">0%</fraction> <fraction name="battery_subpixel_smoothing_right">0%</fraction> + + <!-- Zen mode panel: condition item button padding --> + <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen> + <!-- Zen mode panel: spacing between condition items --> + <dimen name="zen_mode_condition_detail_item_spacing">12dp</dimen> + <!-- Zen mode panel: spacing between two-line condition upper and lower lines --> + <dimen name="zen_mode_condition_detail_item_interline_spacing">4dp</dimen> + <!-- Zen mode panel: bottom padding, a bit less than qs_panel_padding --> + <dimen name="zen_mode_condition_detail_bottom_padding">4dp</dimen> </resources> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 042767d39f84..5dcc927cc5d5 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1025,4 +1025,9 @@ <item quantity="other">%1$d devices connected</item> </plurals> + <!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_manual_zen_more_time">More time.</string> + <!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_manual_zen_less_time">Less time.</string> + </resources> diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml index 3f312f4efda3..bae838749966 100644 --- a/packages/SettingsLib/res/values/styles.xml +++ b/packages/SettingsLib/res/values/styles.xml @@ -21,4 +21,10 @@ <style name="TextAppearanceMedium"> <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> </style> + + <style name="BorderlessButton"> + <item name="android:padding">12dp</item> + <item name="android:background">@drawable/btn_borderless_rect</item> + <item name="android:gravity">center</item> + </style> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenRadioLayout.java index 360907b0d22b..1140028b1ca4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenRadioLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at @@ -12,7 +12,7 @@ * permissions and limitations under the License. */ -package com.android.systemui.volume; +package com.android.settingslib.notification; import android.content.Context; import android.util.AttributeSet; @@ -22,7 +22,7 @@ import android.widget.LinearLayout; /** * Specialized layout for zen mode that allows the radio buttons to reside within - * a RadioGroup, but also makes sure that all the heights off the radio buttons align + * a RadioGroup, but also makes sure that all the heights of the radio buttons align * with the corresponding content in the second child of this view. */ public class ZenRadioLayout extends LinearLayout { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 80ac82576d13..4b2e62c80281 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -323,7 +323,7 @@ </activity> <!-- Springboard for launching the share activity --> - <receiver android:name=".screenshot.GlobalScreenshot$ShareReceiver" + <receiver android:name=".screenshot.GlobalScreenshot$ScreenshotActionReceiver" android:process=":screenshot" android:exported="false" /> diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml new file mode 100644 index 000000000000..ed637a7adcbf --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml @@ -0,0 +1,20 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animator xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="133" + android:valueType="intType" + android:valueFrom="@dimen/car_user_switcher_container_height" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml new file mode 100644 index 000000000000..227c981cb72a --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="167" + android:propertyName="rotation" + android:valueType="floatType" + android:valueFrom="180" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml new file mode 100644 index 000000000000..5901ff41735c --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml @@ -0,0 +1,23 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml new file mode 100644 index 000000000000..41cbe4b104c3 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml @@ -0,0 +1,23 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml new file mode 100644 index 000000000000..341e7e0cdfe9 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:ordering="together" > + + <objectAnimator + android:duration="50" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml new file mode 100644 index 000000000000..6ae74131584d --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml @@ -0,0 +1,20 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animator xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="200" + android:valueType="intType" + android:valueFrom="0" + android:valueTo="@dimen/car_user_switcher_container_height" + android:interpolator="@android:interpolator/fast_out_slow_in" /> diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml new file mode 100644 index 000000000000..06ac9e359b57 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="167" + android:propertyName="rotation" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="180" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml new file mode 100644 index 000000000000..4baefb83a4ef --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="83" + android:startOffset="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="1" + android:valueTo="0" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml new file mode 100644 index 000000000000..2d0deb95da59 --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml @@ -0,0 +1,24 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + + <objectAnimator + android:duration="83" + android:startOffset="83" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml b/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml new file mode 100644 index 000000000000..3315220a60ef --- /dev/null +++ b/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml @@ -0,0 +1,33 @@ +<!-- Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:ordering="together" > + + <objectAnimator + android:duration="167" + android:startOffset="67" + android:propertyName="translationY" + android:valueType="floatType" + android:valueFrom="@dimen/car_user_switcher_container_anim_height" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="83" + android:startOffset="117" + android:propertyName="alpha" + android:valueType="floatType" + android:valueFrom="0" + android:valueTo="1" /> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml index 2c5ad27fe292..d400ed8c7707 100644 --- a/packages/SystemUI/res/drawable/car_ic_arrow.xml +++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright (C) 2015 The Android Open Source Project + ~ Copyright (C) 2017 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. diff --git a/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml b/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml new file mode 100644 index 000000000000..33a512e31675 --- /dev/null +++ b/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml @@ -0,0 +1,24 @@ +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48.0dp" + android:height="48.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M14 28l10-10 10 10z"/> +</vector> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml index 2f16516a6fea..0ee40d7ae47b 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml @@ -15,27 +15,40 @@ limitations under the License. --> -<LinearLayout +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" + android:clipChildren="false" + android:alpha="0" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" > + android:layout_height="@dimen/car_fullscreen_user_pod_height" + android:layout_gravity="center_horizontal|bottom" > <ImageView android:id="@+id/user_avatar" - android:layout_gravity="center" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_image_top" android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width" - android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" /> + android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" + android:layout_above="@id/user_name" /> <TextView android:id="@+id/user_name" android:layout_width="@dimen/car_fullscreen_user_pod_width" android:layout_height="wrap_content" android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_name_top" android:layout_marginBottom="@dimen/car_fullscreen_user_pod_margin_name_bottom" - android:textSize="@dimen/car_fullscreen_user_pod_text_size" + android:textSize="@dimen/car_fullscreen_user_pod_name_text_size" android:textColor="@color/qs_user_detail_name" android:ellipsize="end" android:singleLine="true" android:gravity="center_horizontal" - android:layout_gravity="center_horizontal" /> -</LinearLayout> + android:layout_above="@id/device_name" /> + + <TextView android:id="@+id/device_name" + android:layout_width="@dimen/car_fullscreen_user_pod_width" + android:layout_height="wrap_content" + android:textSize="@dimen/car_fullscreen_user_pod_device_text_size" + android:textColor="@color/qs_user_detail_name" + android:ellipsize="end" + android:singleLine="true" + android:gravity="center_horizontal" + android:layout_alignParentBottom="true" /> +</RelativeLayout> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml index 99d010f2ac2b..d666a203298f 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml @@ -16,10 +16,10 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:clipChildren="false" android:layout_width="match_parent" android:layout_height="wrap_content" - android:gravity="center" - android:layout_gravity="center" > + android:gravity="center" > <!-- car_fullscreen_user_pods will be dynamically added here. --> </LinearLayout> diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml index 257e2814bb65..478b65642689 100644 --- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml +++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml @@ -54,13 +54,13 @@ android:layout_height="wrap_content" android:layout_marginLeft="@dimen/car_margin" android:layout_marginRight="@dimen/car_margin" + android:layout_marginBottom="@dimen/car_user_grid_margin_bottom" android:layout_centerInParent="true" /> <com.android.systemui.statusbar.car.PageIndicator android:id="@+id/user_switcher_page_indicator" android:layout_width="match_parent" android:layout_height="@dimen/car_page_indicator_dot_diameter" - android:layout_marginTop="@dimen/car_page_indicator_margin_top" android:layout_below="@+id/user_grid" /> <Button diff --git a/packages/SystemUI/res/layout/car_qs_footer.xml b/packages/SystemUI/res/layout/car_qs_footer.xml index 044090be9f5d..3afd4ea33039 100644 --- a/packages/SystemUI/res/layout/car_qs_footer.xml +++ b/packages/SystemUI/res/layout/car_qs_footer.xml @@ -35,7 +35,6 @@ android:layout_centerVertical="true" android:layout_width="@dimen/car_qs_footer_icon_width" android:layout_height="@dimen/car_qs_footer_icon_height" - android:layout_marginRight="@dimen/car_qs_footer_user_switch_margin_right" android:background="@drawable/ripple_drawable" android:focusable="true"> @@ -47,6 +46,18 @@ android:scaleType="fitCenter"/> </com.android.systemui.statusbar.phone.MultiUserSwitch> + <ImageView + android:id="@+id/user_switch_expand_icon" + android:layout_height="match_parent" + android:layout_width="@dimen/car_qs_footer_user_switch_icon_width" + android:layout_centerVertical="true" + android:layout_toEndOf="@+id/multi_user_switch" + android:layout_marginLeft="@dimen/car_qs_footer_user_switch_icon_margin" + android:layout_marginRight="@dimen/car_qs_footer_user_switch_icon_margin" + android:src="@drawable/car_ic_arrow_drop_up" + android:scaleType="fitCenter"> + </ImageView> + <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -54,7 +65,7 @@ android:textColor="@color/car_qs_footer_user_name_color" android:gravity="start|center_vertical" android:layout_centerVertical="true" - android:layout_toEndOf="@id/multi_user_switch" /> + android:layout_toEndOf="@id/user_switch_expand_icon" /> <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button" diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml index 4cb0fd5fecfb..7844cac43f9a 100644 --- a/packages/SystemUI/res/layout/car_qs_panel.xml +++ b/packages/SystemUI/res/layout/car_qs_panel.xml @@ -16,6 +16,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/quick_settings_container" + android:clipChildren="false" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/car_qs_background_primary" @@ -26,10 +27,32 @@ <include layout="@layout/car_status_bar_header"/> <include layout="@layout/car_qs_footer"/> - <com.android.systemui.statusbar.car.UserGridView - android:id="@+id/user_grid" + <RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/user_switcher_container" + android:clipChildren="false" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/car_margin" - android:layout_marginRight="@dimen/car_margin" /> + android:layout_height="@dimen/car_user_switcher_container_height" + android:layout_gravity="center_horizontal" > + + <com.android.systemui.statusbar.car.UserGridView + android:id="@+id/user_grid" + android:clipChildren="false" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/car_margin" + android:layout_marginRight="@dimen/car_margin" + android:layout_marginBottom="@dimen/car_user_grid_margin_bottom" + android:layout_above="@id/user_switcher_page_indicator" /> + + <com.android.systemui.statusbar.car.PageIndicator + android:id="@+id/user_switcher_page_indicator" + android:layout_width="match_parent" + android:layout_height="@dimen/car_page_indicator_dot_diameter" + android:layout_marginBottom="@dimen/car_page_indicator_margin_bottom" + android:alpha="0" + android:layout_alignParentBottom="true" /> + + </RelativeLayout> + </LinearLayout> diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml index 3826bdddb1b0..58624135b85f 100644 --- a/packages/SystemUI/res/layout/zen_mode_panel.xml +++ b/packages/SystemUI/res/layout/zen_mode_panel.xml @@ -93,7 +93,7 @@ </RelativeLayout> - <com.android.systemui.volume.ZenRadioLayout + <com.android.settingslib.notification.ZenRadioLayout android:id="@+id/zen_conditions" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -111,7 +111,7 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"/> - </com.android.systemui.volume.ZenRadioLayout> + </com.android.settingslib.notification.ZenRadioLayout> <TextView android:id="@+id/zen_alarm_warning" diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml index 8853587dba47..f3c9f89bad41 100644 --- a/packages/SystemUI/res/values/dimens_car.xml +++ b/packages/SystemUI/res/values/dimens_car.xml @@ -18,20 +18,23 @@ <resources> <dimen name="car_margin">148dp</dimen> + <dimen name="car_fullscreen_user_pod_margin_image_top">24dp</dimen> <dimen name="car_fullscreen_user_pod_margin_name_top">24dp</dimen> - <dimen name="car_fullscreen_user_pod_margin_name_bottom">64dp</dimen> + <dimen name="car_fullscreen_user_pod_margin_name_bottom">20dp</dimen> <dimen name="car_fullscreen_user_pod_margin_between">24dp</dimen> <dimen name="car_fullscreen_user_pod_icon_text_size">96dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_width">192dp</dimen> <dimen name="car_fullscreen_user_pod_image_avatar_height">192dp</dimen> <dimen name="car_fullscreen_user_pod_width">264dp</dimen> - <dimen name="car_fullscreen_user_pod_text_size">40sp</dimen> <!-- B1 --> + <dimen name="car_fullscreen_user_pod_height">356dp</dimen> + <dimen name="car_fullscreen_user_pod_name_text_size">40sp</dimen> <!-- B1 --> + <dimen name="car_fullscreen_user_pod_device_text_size">@dimen/car_body2_size</dimen> <dimen name="car_navigation_button_width">64dp</dimen> <dimen name="car_navigation_bar_width">760dp</dimen> <dimen name="car_page_indicator_dot_diameter">12dp</dimen> - <dimen name="car_page_indicator_margin_top">32dp</dimen> + <dimen name="car_page_indicator_margin_bottom">24dp</dimen> <dimen name="car_user_switcher_progress_bar_height">6dp</dimen> <dimen name="car_user_switcher_progress_bar_margin_top">@dimen/status_bar_height</dimen> @@ -47,8 +50,14 @@ <dimen name="car_qs_footer_padding_start">46dp</dimen> <dimen name="car_qs_footer_icon_width">56dp</dimen> <dimen name="car_qs_footer_icon_height">56dp</dimen> - <dimen name="car_qs_footer_user_switch_margin_right">46dp</dimen> + <dimen name="car_qs_footer_user_switch_icon_margin">5dp</dimen> + <dimen name="car_qs_footer_user_switch_icon_width">36dp</dimen> <dimen name="car_qs_footer_user_name_text_size">@dimen/car_body2_size</dimen> + <dimen name="car_user_switcher_container_height">420dp</dimen> + <!-- This must be the negative of car_user_switcher_container_height for the animation. --> + <dimen name="car_user_switcher_container_anim_height">-420dp</dimen> + <dimen name="car_user_grid_margin_bottom">28dp</dimen> + <dimen name="car_body2_size">26sp</dimen> </resources> diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml index 320ee9f66c79..f84dd4bd5f27 100644 --- a/packages/SystemUI/res/values/integers_car.xml +++ b/packages/SystemUI/res/values/integers_car.xml @@ -19,4 +19,5 @@ <integer name="car_user_switcher_timeout_ms">15000</integer> <!-- This values less than ProgressBar.PROGRESS_ANIM_DURATION for a smooth animation. --> <integer name="car_user_switcher_anim_update_ms">60</integer> + <integer name="car_user_switcher_anim_cascade_delay_ms">27</integer> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ab83bcf23ba5..8d6b38f87801 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -675,6 +675,15 @@ <string name="quick_settings_bluetooth_off_label">Bluetooth Off</string> <!-- QuickSettings: Bluetooth detail panel, text when there are no items [CHAR LIMIT=NONE] --> <string name="quick_settings_bluetooth_detail_empty_text">No paired devices available</string> + <!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]--> + <string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string> + <!-- QuickSettings: Bluetooth secondary label for an audio device being connected [CHAR LIMIT=20]--> + <string name="quick_settings_bluetooth_secondary_label_audio">Audio</string> + <!-- QuickSettings: Bluetooth secondary label for a headset being connected [CHAR LIMIT=20]--> + <string name="quick_settings_bluetooth_secondary_label_headset">Headset</string> + <!-- QuickSettings: Bluetooth secondary label for an input/IO device being connected [CHAR LIMIT=20]--> + <string name="quick_settings_bluetooth_secondary_label_input">Input</string> + <!-- QuickSettings: Brightness [CHAR LIMIT=NONE] --> <string name="quick_settings_brightness_label">Brightness</string> <!-- QuickSettings: Rotation Unlocked [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index d80a33632f3e..9ff681555706 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -333,6 +333,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe */ private class KeyguardSliceButton extends Button { + private static final float SEPARATOR_HEIGHT = 0.7f; private final Paint mPaint; private boolean mHasDivider; @@ -369,7 +370,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe super.onDraw(canvas); if (mHasDivider) { final int lineX = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : getWidth(); - canvas.drawLine(lineX, 0, lineX, getHeight(), mPaint); + final int height = (int) (getHeight() * SEPARATOR_HEIGHT); + final int startY = getHeight() / 2 - height / 2; + canvas.drawLine(lineX, startY, lineX, startY + height, mPaint); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 2873afbca8e9..2b656c220d63 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -171,15 +171,16 @@ public class KeyguardStatusView extends GridLayout { } private void onSliceContentChanged(boolean hasHeader) { - final float clockScale = hasHeader ? mSmallClockScale : 1; + final boolean smallClock = hasHeader || mPulsing; + final float clockScale = smallClock ? mSmallClockScale : 1; float translation = (mClockView.getHeight() - (mClockView.getHeight() * clockScale)) / 2f; - if (hasHeader) { + if (smallClock) { translation -= mWidgetPadding; } mClockView.setTranslationY(translation); mClockView.setScaleX(clockScale); mClockView.setScaleY(clockScale); - mClockSeparator.setVisibility(hasHeader ? VISIBLE : GONE); + mClockSeparator.setVisibility(hasHeader && !mPulsing ? VISIBLE : GONE); } @Override @@ -329,6 +330,8 @@ public class KeyguardStatusView extends GridLayout { public void setPulsing(boolean pulsing) { mPulsing = pulsing; + mKeyguardSlice.setVisibility(pulsing ? GONE : VISIBLE); + onSliceContentChanged(mKeyguardSlice.hasHeader()); updateDozeVisibleViews(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java index 142aab2626a6..23d3ebbbfe80 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java @@ -47,7 +47,7 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, private MultiUserSwitch mMultiUserSwitch; private TextView mUserName; private ImageView mMultiUserAvatar; - private UserGridView mUserGridView; + private CarQSFragment.UserSwitchCallback mUserSwitchCallback; public CarQSFooter(Context context, AttributeSet attrs) { super(context, attrs); @@ -63,15 +63,15 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, mUserInfoController = Dependency.get(UserInfoController.class); mMultiUserSwitch.setOnClickListener(v -> { - if (mUserGridView == null) { + if (mUserSwitchCallback == null) { Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher."); return; } - if (!mUserGridView.isShowing()) { - mUserGridView.show(); + if (!mUserSwitchCallback.isShowing()) { + mUserSwitchCallback.show(); } else { - mUserGridView.hide(); + mUserSwitchCallback.hide(); } }); @@ -102,8 +102,8 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, } } - public void setUserGridView(UserGridView view) { - mUserGridView = view; + public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) { + mUserSwitchCallback = callback; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java index 13298d378845..0ee6d1fb6664 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -13,6 +13,12 @@ */ package com.android.systemui.qs.car; +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; @@ -26,18 +32,29 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFooter; +import com.android.systemui.statusbar.car.PageIndicator; import com.android.systemui.statusbar.car.UserGridView; import com.android.systemui.statusbar.policy.UserSwitcherController; +import java.util.ArrayList; +import java.util.List; + /** * A quick settings fragment for the car. For auto, there is no row for quick settings or ability * to expand the quick settings panel. Instead, the only thing is that displayed is the * status bar, and a static row with access to the user switcher and settings. */ public class CarQSFragment extends Fragment implements QS { + private ViewGroup mPanel; private View mHeader; + private View mUserSwitcherContainer; private CarQSFooter mFooter; + private View mFooterUserName; + private View mFooterExpandIcon; private UserGridView mUserGridView; + private PageIndicator mPageIndicator; + private AnimatorSet mAnimatorSet; + private UserSwitchCallback mUserSwitchCallback; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -48,14 +65,26 @@ public class CarQSFragment extends Fragment implements QS { @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + mPanel = (ViewGroup) view; mHeader = view.findViewById(R.id.header); mFooter = view.findViewById(R.id.qs_footer); + mFooterUserName = mFooter.findViewById(R.id.user_name); + mFooterExpandIcon = mFooter.findViewById(R.id.user_switch_expand_icon); + + mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container); + + updateUserSwitcherHeight(0); mUserGridView = view.findViewById(R.id.user_grid); mUserGridView.init(null, Dependency.get(UserSwitcherController.class), - false /* showInitially */); + false /* overrideAlpha */); - mFooter.setUserGridView(mUserGridView); + mPageIndicator = view.findViewById(R.id.user_switcher_page_indicator); + mPageIndicator.setupWithViewPager(mUserGridView); + + mUserSwitchCallback = new UserSwitchCallback(); + mFooter.setUserSwitchCallback(mUserSwitchCallback); + mUserGridView.setUserSwitchCallback(mUserSwitchCallback); } @Override @@ -82,11 +111,13 @@ public class CarQSFragment extends Fragment implements QS { @Override public void setHeaderListening(boolean listening) { mFooter.setListening(listening); + mUserGridView.setListening(listening); } @Override public void setListening(boolean listening) { mFooter.setListening(listening); + mUserGridView.setListening(listening); } @Override @@ -171,4 +202,126 @@ public class CarQSFragment extends Fragment implements QS { public void setExpandClickListener(OnClickListener onClickListener) { // No ability to expand the quick settings. } + + public class UserSwitchCallback { + private boolean mShowing; + + public boolean isShowing() { + return mShowing; + } + + public void show() { + mShowing = true; + animateHeightChange(true /* opening */); + } + + public void hide() { + mShowing = false; + animateHeightChange(false /* opening */); + } + + public void resetShowing() { + if (mShowing) { + for (int i = 0; i < mUserGridView.getChildCount(); i++) { + ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i); + // Need to bring the last child to the front to maintain the order in the pod + // container. Why? ¯\_(ツ)_/¯ + if (podContainer.getChildCount() > 0) { + podContainer.getChildAt(podContainer.getChildCount() - 1).bringToFront(); + } + // The alpha values are default to 0, so if the pods have been refreshed, they + // need to be set to 1 when showing. + for (int j = 0; j < podContainer.getChildCount(); j++) { + podContainer.getChildAt(j).setAlpha(1f); + } + } + } + } + } + + private void updateUserSwitcherHeight(int height) { + ViewGroup.LayoutParams layoutParams = mUserSwitcherContainer.getLayoutParams(); + layoutParams.height = height; + mUserSwitcherContainer.requestLayout(); + } + + private void animateHeightChange(boolean opening) { + // Animation in progress; cancel it to avoid contention. + if (mAnimatorSet != null){ + mAnimatorSet.cancel(); + } + + List<Animator> allAnimators = new ArrayList<>(); + ValueAnimator heightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_animation + : R.anim.car_user_switcher_close_animation); + heightAnimator.addUpdateListener(valueAnimator -> { + updateUserSwitcherHeight((Integer) valueAnimator.getAnimatedValue()); + }); + allAnimators.add(heightAnimator); + + // The user grid contains pod containers that each contain a number of pods. Animate + // all pods to avoid any discrepancy/race conditions with possible changes during the + // animation. + int cascadeDelay = getResources().getInteger( + R.integer.car_user_switcher_anim_cascade_delay_ms); + for (int i = 0; i < mUserGridView.getChildCount(); i++) { + ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i); + for (int j = 0; j < podContainer.getChildCount(); j++) { + View pod = podContainer.getChildAt(j); + Animator podAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_pod_animation + : R.anim.car_user_switcher_close_pod_animation); + // Add the cascading delay between pods + if (opening) { + podAnimator.setStartDelay(podAnimator.getStartDelay() + j * cascadeDelay); + } + podAnimator.setTarget(pod); + allAnimators.add(podAnimator); + } + } + + Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_name_animation + : R.anim.car_user_switcher_close_name_animation); + nameAnimator.setTarget(mFooterUserName); + allAnimators.add(nameAnimator); + + Animator iconAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_icon_animation + : R.anim.car_user_switcher_close_icon_animation); + iconAnimator.setTarget(mFooterExpandIcon); + allAnimators.add(iconAnimator); + + Animator pageAnimator = AnimatorInflater.loadAnimator(getContext(), + opening ? R.anim.car_user_switcher_open_pages_animation + : R.anim.car_user_switcher_close_pages_animation); + pageAnimator.setTarget(mPageIndicator); + allAnimators.add(pageAnimator); + + mAnimatorSet = new AnimatorSet(); + mAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimatorSet = null; + } + }); + mAnimatorSet.playTogether(allAnimators.toArray(new Animator[0])); + + // Setup all values to the start values in the animations, since there are delays, but need + // to have all values start at the beginning. + setupInitialValues(mAnimatorSet); + + mAnimatorSet.start(); + } + + private void setupInitialValues(Animator anim) { + if (anim instanceof AnimatorSet) { + for (Animator a : ((AnimatorSet) anim).getChildAnimations()) { + setupInitialValues(a); + } + } else if (anim instanceof ObjectAnimator) { + ((ObjectAnimator) anim).setCurrentFraction(0.0f); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index fff9f8e7e038..2607ebbb72ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -18,7 +18,9 @@ package com.android.systemui.qs.tiles; import static com.android.settingslib.graph.BluetoothDeviceLayerDrawable.createLayerDrawable; +import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; @@ -26,7 +28,6 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.provider.Settings; import android.service.quicksettings.Tile; -import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.Switch; @@ -35,6 +36,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; @@ -126,21 +128,25 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { } state.slash.isSlashed = !enabled; state.label = mContext.getString(R.string.quick_settings_bluetooth_label); + if (enabled) { if (connected) { state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected); - state.secondaryLabel = mController.getLastDeviceName(); - CachedBluetoothDevice lastDevice = mController.getLastDevice(); + state.contentDescription = mContext.getString( + R.string.accessibility_bluetooth_name, state.label); + + final CachedBluetoothDevice lastDevice = mController.getLastDevice(); if (lastDevice != null) { - int batteryLevel = lastDevice.getBatteryLevel(); + final int batteryLevel = lastDevice.getBatteryLevel(); if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { - state.icon = new BluetoothBatteryTileIcon(lastDevice, + state.icon = new BluetoothBatteryTileIcon( + batteryLevel, mContext.getResources().getFraction( R.fraction.bt_battery_scale_fraction, 1, 1)); } } - state.contentDescription = mContext.getString( - R.string.accessibility_bluetooth_name, state.secondaryLabel); + + state.label = mController.getLastDeviceName(); } else if (state.isTransient) { state.icon = ResourceIcon.get(R.drawable.ic_bluetooth_transient_animation); state.contentDescription = mContext.getString( @@ -159,11 +165,53 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { state.state = Tile.STATE_INACTIVE; } + state.secondaryLabel = getSecondaryLabel(enabled, connected); + state.dualLabelContentDescription = mContext.getResources().getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); state.expandedAccessibilityClassName = Switch.class.getName(); } + /** + * Returns the secondary label to use for the given bluetooth connection in the form of the + * battery level or bluetooth profile name. If the bluetooth is disabled, there's no connected + * devices, or we can't map the bluetooth class to a profile, this instead returns {@code null}. + * + * @param enabled whether bluetooth is enabled + * @param connected whether there's a device connected via bluetooth + */ + @Nullable + private String getSecondaryLabel(boolean enabled, boolean connected) { + final CachedBluetoothDevice lastDevice = mController.getLastDevice(); + + if (enabled && connected && lastDevice != null) { + final int batteryLevel = lastDevice.getBatteryLevel(); + + if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { + return mContext.getString( + R.string.quick_settings_bluetooth_secondary_label_battery_level, + Utils.formatPercentage(batteryLevel)); + + } else { + final BluetoothClass bluetoothClass = lastDevice.getBtClass(); + if (bluetoothClass != null) { + if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { + return mContext.getString( + R.string.quick_settings_bluetooth_secondary_label_audio); + } else if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { + return mContext.getString( + R.string.quick_settings_bluetooth_secondary_label_headset); + } else if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HID)) { + return mContext.getString( + R.string.quick_settings_bluetooth_secondary_label_input); + } + } + } + } + + return null; + } + @Override public int getMetricsCategory() { return MetricsEvent.QS_BLUETOOTH; @@ -207,20 +255,29 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { return new BluetoothDetailAdapter(); } + /** + * Bluetooth icon wrapper for Quick Settings with a battery indicator that reflects the + * connected device's battery level. This is used instead of + * {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to use a context + * that reflects dark/light theme attributes. + */ private class BluetoothBatteryTileIcon extends Icon { + private int mBatteryLevel; private float mIconScale; - private CachedBluetoothDevice mDevice; - BluetoothBatteryTileIcon(CachedBluetoothDevice device, float iconScale) { + BluetoothBatteryTileIcon(int batteryLevel, float iconScale) { + mBatteryLevel = batteryLevel; mIconScale = iconScale; - mDevice = device; } @Override public Drawable getDrawable(Context context) { // This method returns Pair<Drawable, String> while first value is the drawable - return com.android.settingslib.bluetooth.Utils.getBtClassDrawableWithDescription( - context, mDevice, mIconScale).first; + return BluetoothDeviceLayerDrawable.createLayerDrawable( + context, + R.drawable.ic_qs_bluetooth_connected, + mBatteryLevel, + mIconScale); } } @@ -302,8 +359,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { item.iconResId = R.drawable.ic_qs_bluetooth_connected; int batteryLevel = device.getBatteryLevel(); if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { - item.icon = new BluetoothBatteryTileIcon(device, - 1 /* iconScale */); + item.icon = new BluetoothBatteryTileIcon(batteryLevel,1 /* iconScale */); item.line2 = mContext.getString( R.string.quick_settings_connected_battery_level, Utils.formatPercentage(batteryLevel)); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 675aa8f73a09..0132fa850f95 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -185,7 +185,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // The public notification will show similar info but with the actual screenshot omitted mPublicNotificationBuilder = - new Notification.Builder(context, NotificationChannels.SCREENSHOTS) + new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP) .setContentTitle(r.getString(R.string.screenshot_saving_title)) .setContentText(r.getString(R.string.screenshot_saving_text)) .setSmallIcon(R.drawable.stat_notify_image) @@ -196,7 +196,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { com.android.internal.R.color.system_notification_accent_color)); SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder); - mNotificationBuilder = new Notification.Builder(context, NotificationChannels.SCREENSHOTS) + mNotificationBuilder = new Notification.Builder(context, + NotificationChannels.SCREENSHOTS_HEADSUP) .setTicker(r.getString(R.string.screenshot_saving_ticker) + (mTickerAddSpace ? " " : "")) .setContentTitle(r.getString(R.string.screenshot_saving_title)) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 172c62a99db2..3ec89138d1c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -53,7 +53,7 @@ public class FullscreenUserSwitcher { mParent = containerStub.inflate(); mContainer = mParent.findViewById(R.id.container); mUserGridView = mContainer.findViewById(R.id.user_grid); - mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */); + mUserGridView.init(statusBar, mUserSwitcherController, true /* overrideAlpha */); mUserGridView.setUserSelectionListener(record -> { if (!record.isCurrent) { toggleSwitchInProgress(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java index e551801ca434..1bd820db3f7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java @@ -16,9 +16,6 @@ package com.android.systemui.statusbar.car; -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -29,62 +26,110 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; +import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Vector; + /** * Displays a ViewPager with icons for the users in the system to allow switching between users. * One of the uses of this is for the lock screen in auto. */ -public class UserGridView extends ViewPager { - private static final int EXPAND_ANIMATION_TIME_MS = 200; - private static final int HIDE_ANIMATION_TIME_MS = 133; - +public class UserGridView extends ViewPager implements + UserInfoController.OnUserInfoChangedListener { private StatusBar mStatusBar; private UserSwitcherController mUserSwitcherController; private Adapter mAdapter; private UserSelectionListener mUserSelectionListener; - private ValueAnimator mHeightAnimator; - private int mTargetHeight; - private int mHeightChildren; - private boolean mShowing; + private UserInfoController mUserInfoController; + private Vector mUserContainers; + private int mContainerWidth; + private boolean mOverrideAlpha; + private CarQSFragment.UserSwitchCallback mUserSwitchCallback; public UserGridView(Context context, AttributeSet attrs) { super(context, attrs); } public void init(StatusBar statusBar, UserSwitcherController userSwitcherController, - boolean showInitially) { + boolean overrideAlpha) { mStatusBar = statusBar; mUserSwitcherController = userSwitcherController; mAdapter = new Adapter(mUserSwitcherController); - addOnLayoutChangeListener(mAdapter); - setAdapter(mAdapter); - mShowing = showInitially; + mUserInfoController = Dependency.get(UserInfoController.class); + mOverrideAlpha = overrideAlpha; + // Whenever the container width changes, the containers must be refreshed. Instead of + // doing an initial refreshContainers() to populate the containers, this listener will + // refresh them on layout change because that affects how the users are split into + // containers. Furthermore, at this point, the container width is unknown, so + // refreshContainers() cannot populate any containers. + addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + int newWidth = Math.max(left - right, right - left); + if (mContainerWidth != newWidth) { + mContainerWidth = newWidth; + refreshContainers(); + } + }); } - public boolean isShowing() { - return mShowing; + private void refreshContainers() { + mUserContainers = new Vector(); + + Context context = getContext(); + LayoutInflater inflater = LayoutInflater.from(context); + + for (int i = 0; i < mAdapter.getCount(); i++) { + ViewGroup pods = (ViewGroup) inflater.inflate( + R.layout.car_fullscreen_user_pod_container, null); + + int iconsPerPage = mAdapter.getIconsPerPage(); + int limit = Math.min(mUserSwitcherController.getUsers().size(), (i + 1) * iconsPerPage); + for (int j = i * iconsPerPage; j < limit; j++) { + View v = mAdapter.makeUserPod(inflater, context, j, pods); + if (mOverrideAlpha) { + v.setAlpha(1f); + } + pods.addView(v); + // This is hacky, but the dividers on the pod container LinearLayout don't seem + // to work for whatever reason. Instead, set a right margin on the pod if it's not + // the right-most pod and there is more than one pod in the container. + if (i < limit - 1 && limit > 1) { + ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + params.setMargins(0, 0, getResources().getDimensionPixelSize( + R.dimen.car_fullscreen_user_pod_margin_between), 0); + v.setLayoutParams(params); + } + } + mUserContainers.add(pods); + } + + mAdapter = new Adapter(mUserSwitcherController); + setAdapter(mAdapter); } - public void show() { - mShowing = true; - animateHeightChange(getMeasuredHeight(), mHeightChildren); + @Override + public void onUserInfoChanged(String name, Drawable picture, String userAccount) { + refreshContainers(); } - public void hide() { - mShowing = false; - animateHeightChange(getMeasuredHeight(), 0); + public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) { + mUserSwitchCallback = callback; } public void onUserSwitched(int newUserId) { @@ -96,6 +141,14 @@ public class UserGridView extends ViewPager { mUserSelectionListener = userSelectionListener; } + public void setListening(boolean listening) { + if (listening) { + mUserInfoController.addCallback(this); + } else { + mUserInfoController.removeCallback(this); + } + } + void showOfflineAuthUi() { // TODO: Show keyguard UI in-place. mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true, true); @@ -115,13 +168,6 @@ public class UserGridView extends ViewPager { height = Math.max(child.getMeasuredHeight(), height); } - mHeightChildren = height; - - // Override the height if it's not showing. - if (!mShowing) { - height = 0; - } - // Respect the AT_MOST request from parent. if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height); @@ -132,72 +178,19 @@ public class UserGridView extends ViewPager { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - private void animateHeightChange(int oldHeight, int newHeight) { - // If there is no change in height or an animation is already in progress towards the - // desired height, then there's no need to make any changes. - if (oldHeight == newHeight || newHeight == mTargetHeight) { - return; - } - - // Animation in progress is not going towards the new target, so cancel it. - if (mHeightAnimator != null){ - mHeightAnimator.cancel(); - } - - mTargetHeight = newHeight; - mHeightAnimator = ValueAnimator.ofInt(oldHeight, mTargetHeight); - mHeightAnimator.addUpdateListener(valueAnimator -> { - ViewGroup.LayoutParams layoutParams = getLayoutParams(); - layoutParams.height = (Integer) valueAnimator.getAnimatedValue(); - requestLayout(); - }); - mHeightAnimator.addListener(new AnimatorListener() { - @Override - public void onAnimationStart(Animator animator) {} - - @Override - public void onAnimationEnd(Animator animator) { - // ValueAnimator does not guarantee that the update listener will get an update - // to the final value, so here, the final value is set. Though the final calculated - // height (mTargetHeight) could be set, WRAP_CONTENT is more appropriate. - ViewGroup.LayoutParams layoutParams = getLayoutParams(); - layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; - requestLayout(); - mHeightAnimator = null; - } - - @Override - public void onAnimationCancel(Animator animator) {} - - @Override - public void onAnimationRepeat(Animator animator) {} - }); - - mHeightAnimator.setInterpolator(new FastOutSlowInInterpolator()); - if (oldHeight < newHeight) { - // Expanding - mHeightAnimator.setDuration(EXPAND_ANIMATION_TIME_MS); - } else { - // Hiding - mHeightAnimator.setDuration(HIDE_ANIMATION_TIME_MS); - } - mHeightAnimator.start(); - } - /** * This is a ViewPager.PagerAdapter which deletegates the work to a * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have * to use composition instead to achieve the same goal since both the base classes are abstract * classes and not interfaces. */ - private final class Adapter extends PagerAdapter implements View.OnLayoutChangeListener { + private final class Adapter extends PagerAdapter { private final int mPodWidth; private final int mPodMarginBetween; private final int mPodImageAvatarWidth; private final int mPodImageAvatarHeight; private final WrappedBaseUserAdapter mUserAdapter; - private int mContainerWidth; public Adapter(UserSwitcherController controller) { super(); @@ -229,30 +222,20 @@ public class UserGridView extends ViewPager { } @Override - public Object instantiateItem(ViewGroup container, int position) { - Context context = getContext(); - LayoutInflater inflater = LayoutInflater.from(context); - - ViewGroup pods = (ViewGroup) inflater.inflate( - R.layout.car_fullscreen_user_pod_container, null); + public void finishUpdate(ViewGroup container) { + if (mUserSwitchCallback != null) { + mUserSwitchCallback.resetShowing(); + } + } - int iconsPerPage = getIconsPerPage(); - int limit = Math.min(mUserAdapter.getCount(), (position + 1) * iconsPerPage); - for (int i = position * iconsPerPage; i < limit; i++) { - View v = makeUserPod(inflater, context, i, pods); - pods.addView(v); - // This is hacky, but the dividers on the pod container LinearLayout don't seem - // to work for whatever reason. Instead, set a right margin on the pod if it's not - // the right-most pod and there is more than one pod in the container. - if (i < limit - 1 && limit > 1) { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - params.setMargins(0, 0, mPodMarginBetween, 0); - v.setLayoutParams(params); - } + @Override + public Object instantiateItem(ViewGroup container, int position) { + if (position < mUserContainers.size()) { + container.addView((View) mUserContainers.get(position)); + return mUserContainers.get(position); + } else { + return null; } - container.addView(pods); - return pods; } /** @@ -353,17 +336,10 @@ public class UserGridView extends ViewPager { public boolean isViewFromObject(View view, Object object) { return view == object; } - - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - mContainerWidth = Math.max(left - right, right - left); - notifyDataSetChanged(); - } } private final class WrappedBaseUserAdapter extends UserSwitcherController.BaseUserAdapter { - private Adapter mContainer; + private final Adapter mContainer; public WrappedBaseUserAdapter(UserSwitcherController controller, Adapter container) { super(controller); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 0cc7f5dfbae1..66cb59e3d317 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -72,6 +72,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; +import java.util.Collection; import java.util.List; public class NotificationPanelView extends PanelView implements @@ -2621,8 +2622,10 @@ public class NotificationPanelView extends PanelView implements } } - public void setPulsing(boolean pulsing) { - mKeyguardStatusView.setPulsing(pulsing); + public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) { + mKeyguardStatusView.setPulsing(pulsing != null); + mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1] + + mKeyguardStatusView.getClockBottom()); } public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java index 6fc5bbdd5977..ee1d08872999 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java @@ -28,6 +28,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; +import android.os.SystemProperties; import android.util.Log; import android.util.Slog; import android.view.Display; @@ -131,7 +132,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene new GestureDetector.SimpleOnGestureListener() { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) { - if (mQuickScrubActive) { + if (!isQuickScrubEnabled() || mQuickScrubActive) { return false; } float velocityX = mIsRTL ? -velX : velX; @@ -196,12 +197,13 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene case MotionEvent.ACTION_DOWN: { int x = (int) event.getX(); int y = (int) event.getY(); - if (mHomeButtonRect.contains(x, y)) { + if (isQuickScrubEnabled() && mHomeButtonRect.contains(x, y)) { mTouchDownX = x; mTouchDownY = y; homeButton.setDelayTouchFeedback(true); mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS); } else { + homeButton.setDelayTouchFeedback(false); mTouchDownX = mTouchDownY = -1; } break; @@ -356,6 +358,10 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } } + boolean isQuickScrubEnabled() { + return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", false); + } + private void startQuickScrub() { if (!mQuickScrubActive) { mQuickScrubActive = true; 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 c30fb22630da..3b783c2a079a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -4620,8 +4620,7 @@ public class StatusBar extends SystemUI implements DemoMode, } private void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) { - mStackScroller.setPulsing(pulsing); - mNotificationPanel.setPulsing(pulsing != null); + mNotificationPanel.setPulsing(pulsing); mVisualStabilityManager.setPulsing(pulsing != null); mIgnoreTouchWhilePulsing = false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 443e760d88ae..af3d64be0fd0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -399,6 +399,7 @@ public class NotificationStackScrollLayout extends ViewGroup private final int mSeparatorWidth; private final int mSeparatorThickness; private final Rect mTmpRect = new Rect(); + private int mClockBottom; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -510,7 +511,9 @@ public class NotificationStackScrollLayout extends ViewGroup final int darkTop = (int) (mRegularTopPadding + mSeparatorThickness / 2f); final int darkBottom = darkTop + mSeparatorThickness; - if (mAmbientState.isDark()) { + if (mAmbientState.hasPulsingNotifications()) { + // TODO draw divider between notification and shelf + } else if (mAmbientState.isDark()) { // Only draw divider on AOD if we actually have notifications if (mFirstVisibleBackgroundChild != null) { canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint); @@ -684,7 +687,11 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updateAlgorithmHeightAndPadding() { - mTopPadding = mAmbientState.isDark() ? mDarkTopPadding : mRegularTopPadding; + if (mPulsing != null) { + mTopPadding = mClockBottom; + } else { + mTopPadding = mAmbientState.isDark() ? mDarkTopPadding : mRegularTopPadding; + } mAmbientState.setLayoutHeight(getLayoutHeight()); updateAlgorithmLayoutMinHeight(); mAmbientState.setTopPadding(mTopPadding); @@ -4322,13 +4329,15 @@ public class NotificationStackScrollLayout extends ViewGroup return mIsExpanded; } - public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) { + public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing, int clockBottom) { if (mPulsing == null && pulsing == null) { return; } mPulsing = pulsing; + mClockBottom = clockBottom; mAmbientState.setPulsing(pulsing); updateNotificationAnimationStates(); + updateAlgorithmHeightAndPadding(); updateContentHeight(); notifyHeightChangeListener(mShelf); requestChildrenUpdate(); diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 87bc0e67f7be..14d5c6f52cd0 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -31,7 +31,8 @@ import java.util.Arrays; public class NotificationChannels extends SystemUI { public static String ALERTS = "ALR"; - public static String SCREENSHOTS = "SCN"; + public static String SCREENSHOTS_LEGACY = "SCN"; + public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP"; public static String GENERAL = "GEN"; public static String STORAGE = "DSK"; public static String TVPIP = "TPP"; @@ -56,10 +57,6 @@ public class NotificationChannels extends SystemUI { context.getString(R.string.notification_channel_alerts), NotificationManager.IMPORTANCE_HIGH), new NotificationChannel( - SCREENSHOTS, - context.getString(R.string.notification_channel_screenshot), - NotificationManager.IMPORTANCE_LOW), - new NotificationChannel( GENERAL, context.getString(R.string.notification_channel_general), NotificationManager.IMPORTANCE_MIN), @@ -69,9 +66,18 @@ public class NotificationChannels extends SystemUI { isTv(context) ? NotificationManager.IMPORTANCE_DEFAULT : NotificationManager.IMPORTANCE_LOW), + createScreenshotChannel( + context.getString(R.string.notification_channel_screenshot), + nm.getNotificationChannel(SCREENSHOTS_LEGACY)), batteryChannel )); + // Delete older SS channel if present. + // Screenshots promoted to heads-up in P, this cleans up the lower priority channel from O. + // This line can be deleted in Q. + nm.deleteNotificationChannel(SCREENSHOTS_LEGACY); + + if (isTv(context)) { // TV specific notification channel for TV PIP controls. // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest @@ -83,6 +89,40 @@ public class NotificationChannels extends SystemUI { } } + /** + * Set up screenshot channel, respecting any previously committed user settings on legacy + * channel. + * @return + */ + @VisibleForTesting static NotificationChannel createScreenshotChannel( + String name, NotificationChannel legacySS) { + NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP, + name, NotificationManager.IMPORTANCE_HIGH); // pop on screen + + screenshotChannel.setSound(Uri.parse(""), // silent + new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()); + + if (legacySS != null) { + // Respect any user modified fields from the old channel. + int userlock = legacySS.getUserLockedFields(); + if ((userlock & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0) { + screenshotChannel.setImportance(legacySS.getImportance()); + } + if ((userlock & NotificationChannel.USER_LOCKED_SOUND) != 0) { + screenshotChannel.setSound(legacySS.getSound(), legacySS.getAudioAttributes()); + } + if ((userlock & NotificationChannel.USER_LOCKED_VIBRATION) != 0) { + screenshotChannel.setVibrationPattern(legacySS.getVibrationPattern()); + } + if ((userlock & NotificationChannel.USER_LOCKED_LIGHTS) != 0) { + screenshotChannel.setLightColor(legacySS.getLightColor()); + } + // skip show_badge, irrelevant for system channel + } + + return screenshotChannel; + } + @Override public void start() { createAll(mContext); diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java index 04bdc04a64d9..80dc2c97e1e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java @@ -26,11 +26,14 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; +import android.net.Uri; +import android.provider.Settings; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.NotificationChannels; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,7 +57,7 @@ public class ChannelsTest extends SysuiTestCase { public void testChannelSetup() { Set<String> ALL_CHANNELS = new ArraySet<>(Arrays.asList( NotificationChannels.ALERTS, - NotificationChannels.SCREENSHOTS, + NotificationChannels.SCREENSHOTS_HEADSUP, NotificationChannels.STORAGE, NotificationChannels.GENERAL, NotificationChannels.BATTERY @@ -66,4 +69,52 @@ public class ChannelsTest extends SysuiTestCase { assertEquals(ALL_CHANNELS.size(), list.size()); list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId()))); } + + @Test + public void testChannelSetup_noLegacyScreenshot() { + // Assert old channel cleaned up. + // TODO: remove that code + this test after P. + NotificationChannels.createAll(mContext); + ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); + verify(mMockNotificationManager).deleteNotificationChannel( + NotificationChannels.SCREENSHOTS_LEGACY); + } + + @Test + public void testInheritFromLegacy_keepsUserLockedLegacySettings() { + NotificationChannel legacyChannel = new NotificationChannel("id", "oldName", + NotificationManager.IMPORTANCE_MIN); + legacyChannel.setImportance(NotificationManager.IMPORTANCE_NONE);; + legacyChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, + legacyChannel.getAudioAttributes()); + legacyChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE | + NotificationChannel.USER_LOCKED_SOUND); + NotificationChannel newChannel = + NotificationChannels.createScreenshotChannel("newName", legacyChannel); + // NONE importance user locked, so don't use HIGH for new channel. + assertEquals(NotificationManager.IMPORTANCE_NONE, newChannel.getImportance()); + assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, newChannel.getSound()); + } + + @Test + public void testInheritFromLegacy_dropsUnlockedLegacySettings() { + NotificationChannel legacyChannel = new NotificationChannel("id", "oldName", + NotificationManager.IMPORTANCE_MIN); + NotificationChannel newChannel = + NotificationChannels.createScreenshotChannel("newName", legacyChannel); + assertEquals(Uri.EMPTY, newChannel.getSound()); + assertEquals("newName", newChannel.getName()); + // MIN importance not user locked, so HIGH wins out. + assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance()); + } + + @Test + public void testInheritFromLegacy_noLegacyExists() { + NotificationChannel newChannel = + NotificationChannels.createScreenshotChannel("newName", null); + assertEquals(Uri.EMPTY, newChannel.getSound()); + assertEquals("newName", newChannel.getName()); + assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance()); + } + } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 9b67f8f32704..4144bbd46fb1 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5149,6 +5149,11 @@ message MetricsEvent { // OS: P FUELGAUGE_RESTRICTED_APP_DETAILS = 1285; + // OPEN: Settings > Sound & notification > Do Not Disturb > Turn on now + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/core/Android.bp b/services/core/Android.bp index 3369458595a8..8da6d1e48ffe 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -32,6 +32,7 @@ java_library_static { static_libs: [ "time_zone_distro", "time_zone_distro_installer", + "android.hardware.authsecret-V1.0-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ef6bc437cb6c..24d493e3013e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -571,6 +571,8 @@ public class IpSecService extends IIpSecService.Stub { mConfig = config; mSpi = spi; mSocket = socket; + + spi.setOwnedByTransform(); } public IpSecConfig getConfig() { @@ -651,16 +653,6 @@ public class IpSecService extends IIpSecService.Stub { /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { - if (mOwnedByTransform) { - Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); - // Because SPIs are "handed off" to transform, objects, they should never be - // freed from the SpiRecord once used in a transform. (They refer to the same SA, - // thus ownership and responsibility for freeing these resources passes to the - // Transform object). Thus, we should let the user free them without penalty once - // they are applied in a Transform object. - return; - } - try { mSrvConfig .getNetdInstance() @@ -694,6 +686,10 @@ public class IpSecService extends IIpSecService.Stub { mOwnedByTransform = true; } + public boolean getOwnedByTransform() { + return mOwnedByTransform; + } + @Override public void invalidate() throws RemoteException { getUserRecord().removeSpiRecord(mResourceId); @@ -1107,6 +1103,11 @@ public class IpSecService extends IIpSecService.Stub { // Retrieve SPI record; will throw IllegalArgumentException if not found SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); + // Check to ensure that SPI has not already been used. + if (s.getOwnedByTransform()) { + throw new IllegalStateException("SPI already in use; cannot be used in new Transforms"); + } + // If no remote address is supplied, then use one from the SPI. if (TextUtils.isEmpty(config.getDestinationAddress())) { config.setDestinationAddress(s.getDestinationAddress()); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dc34567532bd..1eec982a0a9a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4711,7 +4711,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .execute(); } @@ -4782,7 +4783,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .setIgnoreTargetSecurity(ignoreTargetSecurity) .execute(); } catch (SecurityException e) { @@ -4818,7 +4820,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .setProfilerInfo(profilerInfo) .setWaitResult(res) .execute(); @@ -4842,7 +4845,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setRequestCode(requestCode) .setStartFlags(startFlags) .setGlobalConfiguration(config) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .execute(); } @@ -4897,7 +4901,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setVoiceInteractor(interactor) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .execute(); } @@ -4912,7 +4917,8 @@ public class ActivityManagerService extends IActivityManager.Stub .setCallingUid(callingUid) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) - .setMayWait(bOptions, userId) + .setActivityOptions(bOptions) + .setMayWait(userId) .execute(); } @@ -4927,6 +4933,7 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException(msg); } + final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options); final int recentsUid = mRecentTasks.getRecentsComponentUid(); final ComponentName recentsComponent = mRecentTasks.getRecentsComponent(); final String recentsPackage = recentsComponent.getPackageName(); @@ -4957,7 +4964,8 @@ public class ActivityManagerService extends IActivityManager.Stub return mActivityStartController.obtainStarter(intent, "startRecentsActivity") .setCallingUid(recentsUid) .setCallingPackage(recentsPackage) - .setMayWait(activityOptions, userId) + .setActivityOptions(safeOptions) + .setMayWait(userId) .execute(); } } finally { @@ -5045,17 +5053,17 @@ public class ActivityManagerService extends IActivityManager.Stub if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - ActivityOptions options = ActivityOptions.fromBundle(bOptions); + SafeActivityOptions options = SafeActivityOptions.fromBundle(bOptions); synchronized (this) { final ActivityRecord r = ActivityRecord.isInStackLocked(callingActivity); if (r == null) { - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return false; } if (r.app == null || r.app.thread == null) { // The caller is not running... d'oh! - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return false; } intent = new Intent(intent); @@ -5100,7 +5108,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (aInfo == null) { // Nobody who is next! - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); if (debug) Slog.d(TAG, "Next matching activity: nothing found"); return false; } @@ -5162,10 +5170,13 @@ public class ActivityManagerService extends IActivityManager.Stub enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS, "startActivityFromRecents()"); + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { - return mStackSupervisor.startActivityFromRecents(taskId, bOptions); + return mStackSupervisor.startActivityFromRecents(callingPid, callingUid, taskId, + SafeActivityOptions.fromBundle(bOptions)); } } finally { Binder.restoreCallingIdentity(origId); @@ -5182,7 +5193,8 @@ public class ActivityManagerService extends IActivityManager.Stub userId, false, ALLOW_FULL_ONLY, reason, null); // TODO: Switch to user app stacks here. int ret = mActivityStartController.startActivities(caller, -1, callingPackage, - intents, resolvedTypes, resultTo, bOptions, userId, reason); + intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, + reason); return ret; } @@ -7941,9 +7953,9 @@ public class ActivityManagerService extends IActivityManager.Stub flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT |PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntentRecord.Key key = new PendingIntentRecord.Key( - type, packageName, activity, resultWho, - requestCode, intents, resolvedTypes, flags, bOptions, userId); + PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, + resultWho, requestCode, intents, resolvedTypes, flags, + SafeActivityOptions.fromBundle(bOptions), userId); WeakReference<PendingIntentRecord> ref; ref = mIntentSenderRecords.get(key); PendingIntentRecord rec = ref != null ? ref.get() : null; @@ -10434,9 +10446,13 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void startInPlaceAnimationOnFrontMostApplication(Bundle opts) throws RemoteException { - final ActivityOptions activityOptions = ActivityOptions.fromBundle(opts); - if (activityOptions.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE || - activityOptions.getCustomInPlaceResId() == 0) { + final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(opts); + final ActivityOptions activityOptions = safeOptions != null + ? safeOptions.getOptions(mStackSupervisor) + : null; + if (activityOptions == null + || activityOptions.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE + || activityOptions.getCustomInPlaceResId() == 0) { throw new IllegalArgumentException("Expected in-place ActivityOption " + "with valid animation"); } @@ -10539,16 +10555,17 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId); synchronized(this) { - moveTaskToFrontLocked(taskId, flags, bOptions, false /* fromRecents */); + moveTaskToFrontLocked(taskId, flags, SafeActivityOptions.fromBundle(bOptions), + false /* fromRecents */); } } - void moveTaskToFrontLocked(int taskId, int flags, Bundle bOptions, boolean fromRecents) { - ActivityOptions options = ActivityOptions.fromBundle(bOptions); + void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options, + boolean fromRecents) { if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), Binder.getCallingUid(), -1, -1, "Task to front")) { - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return; } final long origId = Binder.clearCallingIdentity(); @@ -10562,7 +10579,10 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode"); return; } - mStackSupervisor.findTaskToMoveToFront(task, flags, options, "moveTaskToFront", + ActivityOptions realOptions = options != null + ? options.getOptions(mStackSupervisor) + : null; + mStackSupervisor.findTaskToMoveToFront(task, flags, realOptions, "moveTaskToFront", false /* forceNonResizable */); final ActivityRecord topActivity = task.getTopActivity(); @@ -10576,7 +10596,7 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(origId); } - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); } /** @@ -13534,6 +13554,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean convertToTranslucent(IBinder token, Bundle options) { + SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { @@ -13545,7 +13566,7 @@ public class ActivityManagerService extends IActivityManager.Stub int index = task.mActivities.lastIndexOf(r); if (index > 0) { ActivityRecord under = task.mActivities.get(index - 1); - under.returningOptions = ActivityOptions.fromBundle(options); + under.returningOptions = safeOptions.getOptions(r); } final boolean translucentChanged = r.changeWindowTranslucency(false); if (translucentChanged) { @@ -24909,7 +24930,8 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (ActivityManagerService.this) { return mActivityStartController.startActivitiesInPackage(packageUid, packageName, - intents, resolvedTypes, /*resultTo*/ null, bOptions, userId); + intents, resolvedTypes, null /* resultTo */, + SafeActivityOptions.fromBundle(bOptions), userId); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index eb14bbda4c4b..bfb563fd93a8 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1591,7 +1591,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp, - ActivityRecord resultRecord, ActivityStack resultStack, ActivityOptions options) { + ActivityRecord resultRecord, ActivityStack resultStack) { final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, callingUid); if (startAnyPerm == PERMISSION_GRANTED) { @@ -1645,57 +1645,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D Slog.w(TAG, message); return false; } - if (options != null) { - // If a launch task id is specified, then ensure that the caller is the recents - // component or has the START_TASKS_FROM_RECENTS permission - if (options.getLaunchTaskId() != INVALID_TASK_ID - && !mRecentTasks.isCallerRecents(callingUid)) { - final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS, - callingPid, callingUid); - if (startInTaskPerm == PERMISSION_DENIED) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchTaskId=" - + options.getLaunchTaskId(); - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - } - // Check if someone tries to launch an activity on a private display with a different - // owner. - final int launchDisplayId = options.getLaunchDisplayId(); - if (launchDisplayId != INVALID_DISPLAY && !isCallerAllowedToLaunchOnDisplay(callingPid, - callingUid, launchDisplayId, aInfo)) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with launchDisplayId=" - + launchDisplayId; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - // Check if someone tries to launch an unwhitelisted activity into LockTask mode. - final boolean lockTaskMode = options.getLockTaskMode(); - if (lockTaskMode && !mService.mLockTaskController.isPackageWhitelisted( - UserHandle.getUserId(callingUid), aInfo.packageName)) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with lockTaskMode=true"; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - - // Check permission for remote animations - final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); - if (adapter != null && mService.checkPermission( - CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) - != PERMISSION_GRANTED) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with remoteAnimationAdapter"; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - } return true; } @@ -2166,8 +2115,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, - String reason, boolean forceNonResizeable) { + void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason, + boolean forceNonResizeable) { final ActivityStack currentStack = task.getStack(); if (currentStack == null) { Slog.e(TAG, "findTaskToMoveToFront: can't move task=" @@ -4546,16 +4495,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D task.setTaskDockedResizing(true); } - int startActivityFromRecents(int taskId, Bundle bOptions) { + int startActivityFromRecents(int callingPid, int callingUid, int taskId, + SafeActivityOptions options) { final TaskRecord task; - final int callingUid; final String callingPackage; final Intent intent; final int userId; int activityType = ACTIVITY_TYPE_UNDEFINED; int windowingMode = WINDOWING_MODE_UNDEFINED; - final ActivityOptions activityOptions = (bOptions != null) - ? new ActivityOptions(bOptions) : null; + final ActivityOptions activityOptions = options != null + ? options.getOptions(this) + : null; if (activityOptions != null) { activityType = activityOptions.getLaunchActivityType(); windowingMode = activityOptions.getLaunchWindowingMode(); @@ -4603,7 +4553,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity); mActivityMetricsLogger.notifyActivityLaunching(); try { - mService.moveTaskToFrontLocked(task.taskId, 0, bOptions, + mService.moveTaskToFrontLocked(task.taskId, 0, options, true /* fromRecents */); } finally { mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, @@ -4622,13 +4572,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D task.getStack()); return ActivityManager.START_TASK_TO_FRONT; } - callingUid = task.mCallingUid; callingPackage = task.mCallingPackage; intent = task.intent; intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); userId = task.userId; - int result = mService.getActivityStartController().startActivityInPackage(callingUid, - callingPackage, intent, null, null, null, 0, 0, bOptions, userId, task, + int result = mService.getActivityStartController().startActivityInPackage( + task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null, + null, 0, 0, options, userId, task, "startActivityFromRecents"); if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { setResizingDuringAnimation(task); diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index aed49e0037e1..f9932b20fb5b 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -220,43 +220,44 @@ public class ActivityStartController { } } - final int startActivityInPackage(int uid, String callingPackage, - Intent intent, String resolvedType, IBinder resultTo, - String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId, - TaskRecord inTask, String reason) { + final int startActivityInPackage(int uid, int realCallingUid, int realCallingPid, + String callingPackage, Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, SafeActivityOptions options, + int userId, TaskRecord inTask, String reason) { - userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", - null); + userId = mService.mUserController.handleIncomingUser(realCallingPid, realCallingUid, userId, + false, ALLOW_FULL_ONLY, "startActivityInPackage", null); // TODO: Switch to user app stacks here. return obtainStarter(intent, reason) .setCallingUid(uid) + .setRealCallingPid(realCallingPid) + .setRealCallingUid(realCallingUid) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) - .setMayWait(bOptions, userId) + .setActivityOptions(options) + .setMayWait(userId) .setInTask(inTask) .execute(); } final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, - String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId) { + String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId) { final String reason = "startActivityInPackage"; userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null); // TODO: Switch to user app stacks here. - int ret = startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, - bOptions, userId, reason); - return ret; + return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options, + userId, reason); } int startActivities(IApplicationThread caller, int callingUid, String callingPackage, - Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId, - String reason) { + Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, + int userId, String reason) { if (intents == null) { throw new NullPointerException("intents is null"); } @@ -312,9 +313,9 @@ public class ActivityStartController { "FLAG_CANT_SAVE_STATE not supported here"); } - ActivityOptions options = ActivityOptions.fromBundle( - i == intents.length - 1 ? bOptions : null); - + final SafeActivityOptions checkedOptions = i == intents.length - 1 + ? options + : null; final int res = obtainStarter(intent, reason) .setCaller(caller) .setResolvedType(resolvedTypes[i]) @@ -326,7 +327,7 @@ public class ActivityStartController { .setCallingPackage(callingPackage) .setRealCallingPid(realCallingPid) .setRealCallingUid(realCallingUid) - .setActivityOptions(options) + .setActivityOptions(checkedOptions) .setComponentSpecified(componentSpecified) .setOutActivity(outActivity) .execute(); diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 3a13155d88e1..8595aa394800 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -74,6 +74,7 @@ import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IApplicationThread; @@ -298,7 +299,7 @@ class ActivityStarter { int realCallingPid; int realCallingUid; int startFlags; - ActivityOptions activityOptions; + SafeActivityOptions activityOptions; boolean ignoreTargetSecurity; boolean componentSpecified; ActivityRecord[] outActivity; @@ -306,13 +307,12 @@ class ActivityStarter { String reason; ProfilerInfo profilerInfo; Configuration globalConfig; - Bundle waitOptions; int userId; WaitResult waitResult; /** * Indicates that we should wait for the result of the start request. This flag is set when - * {@link ActivityStarter#setMayWait(Bundle, int)} is called. + * {@link ActivityStarter#setMayWait(int)} is called. * {@see ActivityStarter#startActivityMayWait}. */ boolean mayWait; @@ -353,7 +353,6 @@ class ActivityStarter { reason = null; profilerInfo = null; globalConfig = null; - waitOptions = null; userId = 0; waitResult = null; mayWait = false; @@ -388,7 +387,6 @@ class ActivityStarter { reason = request.reason; profilerInfo = request.profilerInfo; globalConfig = request.globalConfig; - waitOptions = request.waitOptions; userId = request.userId; waitResult = request.waitResult; mayWait = request.mayWait; @@ -473,7 +471,7 @@ class ActivityStarter { mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, - mRequest.waitOptions, mRequest.ignoreTargetSecurity, mRequest.userId, + mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, @@ -513,7 +511,7 @@ class ActivityStarter { IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, - ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, + SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, String reason) { if (TextUtils.isEmpty(reason)) { @@ -555,8 +553,9 @@ class ActivityStarter { IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, - ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, - ActivityRecord[] outActivity, TaskRecord inTask) { + SafeActivityOptions options, + boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, + TaskRecord inTask) { int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. final Bundle verificationBundle @@ -603,7 +602,7 @@ class ActivityStarter { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; @@ -691,16 +690,20 @@ class ActivityStarter { resultStack.sendActivityResultLocked( -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null); } - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return err; } boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho, - requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp, - resultRecord, resultStack, options); + requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, + callerApp, resultRecord, resultStack); abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); + // Merge the two options bundles, while realCallerOptions takes precedence. + ActivityOptions checkedOptions = options != null + ? options.getOptions(intent, aInfo, callerApp, mSupervisor) + : null; if (mService.mController != null) { try { // The Intent we give to the watcher has the extra data @@ -715,7 +718,7 @@ class ActivityStarter { mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage); if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, - callingUid, options)) { + callingUid, checkedOptions)) { // activity start was intercepted, e.g. because the target user is currently in quiet // mode (turn off work) or the target application is suspended intent = mInterceptor.mIntent; @@ -725,7 +728,7 @@ class ActivityStarter { inTask = mInterceptor.mInTask; callingPid = mInterceptor.mCallingPid; callingUid = mInterceptor.mCallingUid; - options = mInterceptor.mActivityOptions; + checkedOptions = mInterceptor.mActivityOptions; } if (abort) { @@ -735,7 +738,7 @@ class ActivityStarter { } // We pretend to the caller that it was really started, but // they will just get a cancel result. - ActivityOptions.abort(options); + ActivityOptions.abort(checkedOptions); return START_ABORTED; } @@ -796,7 +799,7 @@ class ActivityStarter { ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, - mSupervisor, options, sourceRecord); + mSupervisor, checkedOptions, sourceRecord); if (outActivity != null) { outActivity[0] = r; } @@ -808,13 +811,16 @@ class ActivityStarter { } final ActivityStack stack = mSupervisor.mFocusedStack; + + // If we are starting an activity that is not from the same uid as the currently resumed + // one, check whether app switches are allowed. if (voiceSession == null && (stack.mResumedActivity == null - || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) { + || stack.mResumedActivity.info.applicationInfo.uid != realCallingUid)) { if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid, "Activity start")) { mController.addPendingActivityLaunch(new PendingActivityLaunch(r, sourceRecord, startFlags, stack, callerApp)); - ActivityOptions.abort(options); + ActivityOptions.abort(checkedOptions); return ActivityManager.START_SWITCHES_CANCELED; } } @@ -833,9 +839,10 @@ class ActivityStarter { mController.doPendingActivityLaunches(false); return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, - true /* doResume */, options, inTask, outActivity); + true /* doResume */, checkedOptions, inTask, outActivity); } + /** * Creates a launch intent for the given auxiliary resolution data. */ @@ -900,8 +907,8 @@ class ActivityStarter { IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, - Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId, - TaskRecord inTask, String reason) { + Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, + int userId, TaskRecord inTask, String reason) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -953,7 +960,6 @@ class ActivityStarter { // Collect information about the target of the Intent. ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); - ActivityOptions options = ActivityOptions.fromBundle(bOptions); synchronized (mService) { final int realCallingPid = Binder.getCallingPid(); final int realCallingUid = Binder.getCallingUid(); @@ -993,7 +999,7 @@ class ActivityStarter { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); - ActivityOptions.abort(options); + SafeActivityOptions.abort(options); return ActivityManager.START_PERMISSION_DENIED; } } @@ -1039,12 +1045,10 @@ class ActivityStarter { } final ActivityRecord[] outRecord = new ActivityRecord[1]; - int res = startActivity(caller, intent, ephemeralIntent, resolvedType, - aInfo, rInfo, voiceSession, voiceInteractor, - resultTo, resultWho, requestCode, callingPid, - callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, - options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, - reason); + int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, + voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, + callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, + ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason); Binder.restoreCallingIdentity(origId); @@ -1248,7 +1252,7 @@ class ActivityStarter { outActivity[0] = reusedActivity; } - return START_TASK_TO_FRONT; + return START_DELIVERED_TO_TOP; } } @@ -2447,11 +2451,15 @@ class ActivityStarter { return this; } - ActivityStarter setActivityOptions(ActivityOptions options) { + ActivityStarter setActivityOptions(SafeActivityOptions options) { mRequest.activityOptions = options; return this; } + ActivityStarter setActivityOptions(Bundle bOptions) { + return setActivityOptions(SafeActivityOptions.fromBundle(bOptions)); + } + ActivityStarter setIgnoreTargetSecurity(boolean ignoreTargetSecurity) { mRequest.ignoreTargetSecurity = ignoreTargetSecurity; return this; @@ -2487,19 +2495,13 @@ class ActivityStarter { return this; } - ActivityStarter setWaitOptions(Bundle options) { - mRequest.waitOptions = options; - return this; - } - ActivityStarter setUserId(int userId) { mRequest.userId = userId; return this; } - ActivityStarter setMayWait(Bundle options, int userId) { + ActivityStarter setMayWait(int userId) { mRequest.mayWait = true; - mRequest.waitOptions = options; mRequest.userId = userId; return this; diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 26d65bc7414c..0da7e0ec2f6d 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -408,9 +408,11 @@ class AppErrors { final Set<String> cats = task.intent.getCategories(); if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) { mService.getActivityStartController().startActivityInPackage( - task.mCallingUid, task.mCallingPackage, task.intent, null, null, - null, 0, 0, ActivityOptions.makeBasic().toBundle(), task.userId, - null, "AppErrors"); + task.mCallingUid, callingPid, callingUid, task.mCallingPackage, + task.intent, null, null, null, 0, 0, + new SafeActivityOptions(ActivityOptions.makeBasic()), + task.userId, null, + "AppErrors"); } } } diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java index f821f6bdb925..5f5a504bb014 100644 --- a/services/core/java/com/android/server/am/AppTaskImpl.java +++ b/services/core/java/com/android/server/am/AppTaskImpl.java @@ -20,6 +20,7 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.IAppTask; import android.app.IApplicationThread; import android.content.Intent; @@ -93,10 +94,13 @@ class AppTaskImpl extends IAppTask.Stub { public void moveToFront() { checkCaller(); // Will bring task to front if it already has a root activity. + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { - mService.mStackSupervisor.startActivityFromRecents(mTaskId, null); + mService.mStackSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId, + null); } } finally { Binder.restoreCallingIdentity(origId); @@ -127,7 +131,8 @@ class AppTaskImpl extends IAppTask.Stub { .setCaller(appThread) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) - .setMayWait(bOptions, callingUser) + .setActivityOptions(bOptions) + .setMayWait(callingUser) .setInTask(tr) .execute(); } diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index c26e7703a1ca..8e9d85d60479 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -16,10 +16,12 @@ package com.android.server.am; +import static android.app.ActivityManager.START_SUCCESS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.content.IIntentSender; import android.content.IIntentReceiver; import android.app.PendingIntent; @@ -65,7 +67,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { final int requestCode; final Intent requestIntent; final String requestResolvedType; - final Bundle options; + final SafeActivityOptions options; Intent[] allIntents; String[] allResolvedTypes; final int flags; @@ -75,7 +77,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { private static final int ODD_PRIME_NUMBER = 37; Key(int _t, String _p, ActivityRecord _a, String _w, - int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) { + int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) { type = _t; packageName = _p; activity = _a; @@ -310,17 +312,16 @@ final class PendingIntentRecord extends IIntentSender.Stub { if (userId == UserHandle.USER_CURRENT) { userId = owner.mUserController.getCurrentOrTargetUserId(); } - int res = 0; + int res = START_SUCCESS; switch (key.type) { case ActivityManager.INTENT_SENDER_ACTIVITY: - if (options == null) { - options = key.options; - } else if (key.options != null) { - Bundle opts = new Bundle(key.options); - opts.putAll(options); - options = opts; - } try { + SafeActivityOptions mergedOptions = key.options; + if (mergedOptions == null) { + mergedOptions = SafeActivityOptions.fromBundle(options); + } else { + mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); + } if (key.allIntents != null && key.allIntents.length > 1) { Intent[] allIntents = new Intent[key.allIntents.length]; String[] allResolvedTypes = new String[key.allIntents.length]; @@ -332,14 +333,14 @@ final class PendingIntentRecord extends IIntentSender.Stub { } allIntents[allIntents.length-1] = finalIntent; allResolvedTypes[allResolvedTypes.length-1] = resolvedType; - owner.getActivityStartController().startActivitiesInPackage(uid, - key.packageName, allIntents, allResolvedTypes, resultTo, - options, userId); + res = owner.getActivityStartController().startActivitiesInPackage( + uid, key.packageName, allIntents, allResolvedTypes, + resultTo, mergedOptions, userId); } else { - owner.getActivityStartController().startActivityInPackage(uid, - key.packageName, finalIntent, resolvedType, resultTo, - resultWho, requestCode, 0, options, userId, null, - "PendingIntentRecord"); + res = owner.getActivityStartController().startActivityInPackage(uid, + callingPid, callingUid, key.packageName, finalIntent, + resolvedType, resultTo, resultWho, requestCode, 0, + mergedOptions, userId, null, "PendingIntentRecord"); } } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startActivity intent", e); diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java new file mode 100644 index 000000000000..d08111ec0aa5 --- /dev/null +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.am; + +import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; +import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.view.Display.INVALID_DISPLAY; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.TaskRecord.INVALID_TASK_ID; + +import android.annotation.Nullable; +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Binder; +import android.os.Bundle; +import android.os.UserHandle; +import android.util.Slog; +import android.view.RemoteAnimationAdapter; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Wraps {@link ActivityOptions}, records binder identity, and checks permission when retrieving + * the inner options. Also supports having two set of options: Once from the original caller, and + * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. + */ +class SafeActivityOptions { + + private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM; + + private final int mOriginalCallingPid; + private final int mOriginalCallingUid; + private int mRealCallingPid; + private int mRealCallingUid; + private final @Nullable ActivityOptions mOriginalOptions; + private @Nullable ActivityOptions mCallerOptions; + + /** + * Constructs a new instance from a bundle and records {@link Binder#getCallingPid}/ + * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing + * this object. + * + * @param bOptions The {@link ActivityOptions} as {@link Bundle}. + */ + static SafeActivityOptions fromBundle(Bundle bOptions) { + return bOptions != null + ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions)) + : null; + } + + /** + * Constructs a new instance and records {@link Binder#getCallingPid}/ + * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing + * this object. + * + * @param options The options to wrap. + */ + SafeActivityOptions(@Nullable ActivityOptions options) { + mOriginalCallingPid = Binder.getCallingPid(); + mOriginalCallingUid = Binder.getCallingUid(); + mOriginalOptions = options; + } + + /** + * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ + * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this + * method. + */ + void setCallerOptions(@Nullable ActivityOptions options) { + mRealCallingPid = Binder.getCallingPid(); + mRealCallingUid = Binder.getCallingUid(); + mCallerOptions = options; + } + + /** + * Performs permission check and retrieves the options. + * + * @param r The record of the being started activity. + */ + ActivityOptions getOptions(ActivityRecord r) throws SecurityException { + return getOptions(r.intent, r.info, r.app, r.mStackSupervisor); + } + + /** + * Performs permission check and retrieves the options when options are not being used to launch + * a specific activity (i.e. a task is moved to front). + */ + ActivityOptions getOptions(ActivityStackSupervisor supervisor) throws SecurityException { + return getOptions(null, null, null, supervisor); + } + + /** + * Performs permission check and retrieves the options. + * + * @param intent The intent that is being launched. + * @param aInfo The info of the activity being launched. + * @param callerApp The record of the caller. + */ + ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, + @Nullable ProcessRecord callerApp, + ActivityStackSupervisor supervisor) throws SecurityException { + if (mOriginalOptions != null) { + checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, + mOriginalCallingPid, mOriginalCallingUid); + } + if (mCallerOptions != null) { + checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, + mRealCallingPid, mRealCallingUid); + } + return mergeActivityOptions(mOriginalOptions, mCallerOptions); + } + + /** + * @see ActivityOptions#popAppVerificationBundle + */ + Bundle popAppVerificationBundle() { + return mOriginalOptions != null ? mOriginalOptions.popAppVerificationBundle() : null; + } + + private void abort() { + if (mOriginalOptions != null) { + ActivityOptions.abort(mOriginalOptions); + } + if (mCallerOptions != null) { + ActivityOptions.abort(mCallerOptions); + } + } + + static void abort(@Nullable SafeActivityOptions options) { + if (options != null) { + options.abort(); + } + } + + /** + * Merges two activity options into one, with {@code options2} taking precedence in case of a + * conflict. + */ + @VisibleForTesting + @Nullable ActivityOptions mergeActivityOptions(@Nullable ActivityOptions options1, + @Nullable ActivityOptions options2) { + if (options1 == null) { + return options2; + } + if (options2 == null) { + return options1; + } + final Bundle b1 = options1.toBundle(); + final Bundle b2 = options2.toBundle(); + b1.putAll(b2); + return ActivityOptions.fromBundle(b1); + } + + private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, + @Nullable ProcessRecord callerApp, ActivityStackSupervisor supervisor, + ActivityOptions options, int callingPid, int callingUid) { + // If a launch task id is specified, then ensure that the caller is the recents + // component or has the START_TASKS_FROM_RECENTS permission + if (options.getLaunchTaskId() != INVALID_TASK_ID + && !supervisor.mRecentTasks.isCallerRecents(callingUid)) { + final int startInTaskPerm = supervisor.mService.checkPermission( + START_TASKS_FROM_RECENTS, callingPid, callingUid); + if (startInTaskPerm == PERMISSION_DENIED) { + final String msg = "Permission Denial: starting " + getIntentString(intent) + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchTaskId=" + + options.getLaunchTaskId(); + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + // Check if someone tries to launch an activity on a private display with a different + // owner. + final int launchDisplayId = options.getLaunchDisplayId(); + if (aInfo != null && launchDisplayId != INVALID_DISPLAY + && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, + launchDisplayId, aInfo)) { + final String msg = "Permission Denial: starting " + getIntentString(intent) + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with launchDisplayId=" + + launchDisplayId; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + // Check if someone tries to launch an unwhitelisted activity into LockTask mode. + final boolean lockTaskMode = options.getLockTaskMode(); + if (aInfo != null && lockTaskMode + && !supervisor.mService.mLockTaskController.isPackageWhitelisted( + UserHandle.getUserId(callingUid), aInfo.packageName)) { + final String msg = "Permission Denial: starting " + getIntentString(intent) + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with lockTaskMode=true"; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + + // Check permission for remote animations + final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); + if (adapter != null && supervisor.mService.checkPermission( + CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) + != PERMISSION_GRANTED) { + final String msg = "Permission Denial: starting " + getIntentString(intent) + + " from " + callerApp + " (pid=" + callingPid + + ", uid=" + callingUid + ") with remoteAnimationAdapter"; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + + private String getIntentString(Intent intent) { + return intent != null ? intent.toString() : "(no intent)"; + } +} diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index b97de6511aed..c77ec20afa3b 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1849,7 +1849,6 @@ public final class DisplayManagerService extends SystemService { if (packageName != null && !validatePackageName(getCallingUid(), packageName)) { packageName = null; } - Preconditions.checkNotNull(c); final long token = Binder.clearCallingIdentity(); try { setBrightnessConfigurationForUserInternal(c, userId, packageName); diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java index f1ce5c5f0007..cbf46f832186 100644 --- a/services/core/java/com/android/server/display/PersistentDataStore.java +++ b/services/core/java/com/android/server/display/PersistentDataStore.java @@ -598,14 +598,20 @@ final class PersistentDataStore { private boolean setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial, String packageName) { BrightnessConfiguration currentConfig = mConfigurations.get(userSerial); - if (currentConfig == null || !currentConfig.equals(c)) { - if (packageName == null) { - mPackageNames.remove(userSerial); + if (currentConfig != c && (currentConfig == null || !currentConfig.equals(c))) { + if (c != null) { + if (packageName == null) { + mPackageNames.remove(userSerial); + } else { + mPackageNames.put(userSerial, packageName); + } + mTimeStamps.put(userSerial, System.currentTimeMillis()); + mConfigurations.put(userSerial, c); } else { - mPackageNames.put(userSerial, packageName); + mPackageNames.remove(userSerial); + mTimeStamps.delete(userSerial); + mConfigurations.remove(userSerial); } - mTimeStamps.put(userSerial, System.currentTimeMillis()); - mConfigurations.put(userSerial, c); return true; } return false; diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 0f5cb0a38c83..611f4ec7b865 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -1054,6 +1054,14 @@ public final class JobStatus { if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) { pw.print(" DEVICE_NOT_DOZING"); } + if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) { + pw.print(" BACKGROUND_NOT_RESTRICTED"); + } + if (constraints != 0) { + pw.print(" [0x"); + pw.print(Integer.toHexString(constraints)); + pw.print("]"); + } } /** Writes constraints to the given repeating proto field. */ diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 07ea51be4ba0..a6753ab09103 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -53,6 +53,7 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; +import android.hardware.authsecret.V1_0.IAuthSecret; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -77,10 +78,10 @@ import android.security.KeyStore; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; -import android.security.keystore.KeychainProtectionParams; import android.security.keystore.UserNotAuthenticatedException; -import android.security.keystore.WrappedApplicationKey; -import android.security.keystore.KeychainSnapshot; +import android.security.keystore.recovery.KeychainProtectionParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.security.keystore.recovery.KeychainSnapshot; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; import android.text.TextUtils; @@ -126,8 +127,10 @@ import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -183,6 +186,7 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean mFirstCallToVold; protected IGateKeeperService mGateKeeperService; + protected IAuthSecret mAuthSecretService; /** * The UIDs that are used for system credential storage in keystore. @@ -613,6 +617,14 @@ public class LockSettingsService extends ILockSettings.Stub { } catch (RemoteException e) { Slog.e(TAG, "Failure retrieving IGateKeeperService", e); } + // Find the AuthSecret HAL + try { + mAuthSecretService = IAuthSecret.getService(); + } catch (NoSuchElementException e) { + Slog.i(TAG, "Device doesn't implement AuthSecret HAL"); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to get AuthSecret HAL", e); + } mDeviceProvisionedObserver.onSystemReady(); // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); @@ -2127,6 +2139,20 @@ public class LockSettingsService extends ILockSettings.Stub { private SparseArray<AuthenticationToken> mSpCache = new SparseArray(); private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { + // Pass the primary user's auth secret to the HAL + if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) { + try { + final byte[] rawSecret = auth.deriveVendorAuthSecret(); + final ArrayList<Byte> secret = new ArrayList<>(rawSecret.length); + for (int i = 0; i < rawSecret.length; ++i) { + secret.add(rawSecret[i]); + } + mAuthSecretService.primaryUserCredential(secret); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e); + } + } + // Update the SP cache, removing the entry when allowed synchronized (mSpManager) { if (shouldCacheSpForUser(userId)) { diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 7a3a746e1868..88b2a3685088 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -121,6 +121,7 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALIZATION_USER_GK_AUTH = "user-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes(); private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes(); + private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes(); private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes(); private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes(); private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); @@ -159,6 +160,11 @@ public class SyntheticPasswordManager { syntheticPassword.getBytes()); } + public byte[] deriveVendorAuthSecret() { + return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, + syntheticPassword.getBytes()); + } + private void initialize(byte[] P0, byte[] P1) { this.P1 = P1; this.syntheticPassword = String.valueOf(HexEncoding.encode( diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index 452c9eea79e8..6fcbcbcbfad9 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -16,14 +16,14 @@ package com.android.server.locksettings.recoverablekeystore; -import static android.security.keystore.KeychainProtectionParams.TYPE_LOCKSCREEN; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN; import android.annotation.Nullable; import android.content.Context; -import android.security.keystore.KeyDerivationParams; -import android.security.keystore.KeychainProtectionParams; -import android.security.keystore.KeychainSnapshot; -import android.security.keystore.WrappedApplicationKey; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.KeychainProtectionParams; +import android.security.keystore.recovery.KeychainSnapshot; +import android.security.keystore.recovery.WrappedApplicationKey; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 76508d5817e2..ac3cef2fa7ef 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -33,10 +33,10 @@ import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; -import android.security.keystore.KeychainProtectionParams; -import android.security.keystore.KeychainSnapshot; -import android.security.keystore.RecoveryController; -import android.security.keystore.WrappedApplicationKey; +import android.security.keystore.recovery.KeychainProtectionParams; +import android.security.keystore.recovery.KeychainSnapshot; +import android.security.keystore.recovery.RecoveryController; +import android.security.keystore.recovery.WrappedApplicationKey; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java index 62bb41ec48aa..7cde7ab0589c 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java @@ -17,7 +17,7 @@ package com.android.server.locksettings.recoverablekeystore.storage; import android.annotation.Nullable; -import android.security.keystore.KeychainSnapshot; +import android.security.keystore.recovery.KeychainSnapshot; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 2bd9cab313a7..b4bc7f507701 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -37,6 +37,7 @@ import com.android.server.am.ProcessList; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; +import java.util.Set; public class NetworkPolicyLogger { static final String TAG = "NetworkPolicy"; @@ -62,6 +63,7 @@ public class NetworkPolicyLogger { private static final int EVENT_TEMP_POWER_SAVE_WL_CHANGED = 10; private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11; private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12; + private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13; static final int NTWK_BLOCKED_POWER = 0; static final int NTWK_ALLOWED_NON_METERED = 1; @@ -179,6 +181,14 @@ public class NetworkPolicyLogger { } } + void meteredRestrictedPkgsChanged(Set<Integer> restrictedUids) { + synchronized (mLock) { + final String log = "Metered restricted uids: " + restrictedUids; + if (LOGD) Slog.d(TAG, log); + mEventsBuffer.event(log); + } + } + void dumpLogs(IndentingPrintWriter pw) { synchronized (mLock) { pw.println(); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 971ac8b922ef..649096442da8 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -19,6 +19,8 @@ package com.android.server.net; import android.net.Network; import android.telephony.SubscriptionPlan; +import java.util.Set; + /** * Network Policy Manager local system service interface. * @@ -71,4 +73,21 @@ public abstract class NetworkPolicyManagerInternal { * Informs that admin data is loaded and available. */ public abstract void onAdminDataAvailable(); + + /** + * Sets a list of packages which are restricted by admin from accessing metered data. + * + * @param packageNames the list of restricted packages. + * @param userId the userId in which {@param packagesNames} are restricted. + */ + public abstract void setMeteredRestrictedPackages( + Set<String> packageNames, int userId); + + + /** + * Similar to {@link #setMeteredRestrictedPackages(Set, int)} but updates the restricted + * packages list asynchronously. + */ + public abstract void setMeteredRestrictedPackagesAsync( + Set<String> packageNames, int userId); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e406d51ac823..0e54768bfa87 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -232,6 +232,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -349,6 +350,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_POLICIES_CHANGED = 13; private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15; private static final int MSG_SUBSCRIPTION_OVERRIDE = 16; + private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -480,6 +482,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mNetworkPoliciesSecondLock") private final SparseIntArray mNetIdToSubId = new SparseIntArray(); + /** + * Indicates the uids restricted by admin from accessing metered data. It's a mapping from + * userId to restricted uids which belong to that user. + */ + @GuardedBy("mUidRulesFirstLock") + private final SparseArray<Set<Integer>> mMeteredRestrictedUids = new SparseArray<>(); + private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); @@ -898,6 +907,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Remove any persistable state for the given user; both cleaning up after a // USER_REMOVED, and one last sanity check during USER_ADDED removeUserStateUL(userId, true); + // Removing outside removeUserStateUL since that can also be called when + // user resets app preferences. + mMeteredRestrictedUids.remove(userId); if (action == ACTION_USER_ADDED) { // Add apps that are whitelisted by default. addDefaultRestrictBackgroundWhitelistUidsUL(userId); @@ -3137,6 +3149,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } fout.decreaseIndent(); + fout.println("Admin restricted uids for metered data:"); + fout.increaseIndent(); + size = mMeteredRestrictedUids.size(); + for (int i = 0; i < size; ++i) { + fout.print("u" + mMeteredRestrictedUids.keyAt(i) + ": "); + fout.println(mMeteredRestrictedUids.valueAt(i)); + } + fout.decreaseIndent(); + mLogger.dumpLogs(fout); } } @@ -3705,6 +3726,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final int oldUidRules = mUidRules.get(uid, RULE_NONE); final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); + final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isWhitelisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; @@ -3712,7 +3734,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int newRule = RULE_NONE; // First step: define the new rule based on user restrictions and foreground state. - if (isForeground) { + if (isRestrictedByAdmin) { + newRule = RULE_REJECT_METERED; + } else if (isForeground) { if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) { newRule = RULE_TEMPORARY_ALLOW_METERED; } else if (isWhitelisted) { @@ -3732,6 +3756,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + ": isForeground=" +isForeground + ", isBlacklisted=" + isBlacklisted + ", isWhitelisted=" + isWhitelisted + + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", oldRule=" + uidRulesToString(oldRule) + ", newRule=" + uidRulesToString(newRule) + ", newUidRules=" + uidRulesToString(newUidRules) @@ -3767,13 +3792,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (!isWhitelisted) { setMeteredNetworkWhitelist(uid, false); } - if (isBlacklisted) { + if (isBlacklisted || isRestrictedByAdmin) { setMeteredNetworkBlacklist(uid, true); } } else if (hasRule(newRule, RULE_REJECT_METERED) || hasRule(oldRule, RULE_REJECT_METERED)) { // Flip state because app was explicitly added or removed to blacklist. - setMeteredNetworkBlacklist(uid, isBlacklisted); + setMeteredNetworkBlacklist(uid, (isBlacklisted || isRestrictedByAdmin)); if (hasRule(oldRule, RULE_REJECT_METERED) && isWhitelisted) { // Since blacklist prevails over whitelist, we need to handle the special case // where app is whitelisted and blacklisted at the same time (although such @@ -3790,6 +3815,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted + ", blacklisted=" + isBlacklisted + + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", newRule=" + uidRulesToString(newUidRules) + ", oldRule=" + uidRulesToString(oldUidRules)); } @@ -4102,6 +4128,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_METERED_RESTRICTED_PACKAGES_CHANGED: { + final int userId = msg.arg1; + final Set<String> packageNames = (Set<String>) msg.obj; + setMeteredRestrictedPackagesInternal(packageNames, userId); + return true; + } default: { return false; } @@ -4605,6 +4637,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public void onAdminDataAvailable() { mAdminDataAvailableLatch.countDown(); } + + @Override + public void setMeteredRestrictedPackages(Set<String> packageNames, int userId) { + setMeteredRestrictedPackagesInternal(packageNames, userId); + } + + @Override + public void setMeteredRestrictedPackagesAsync(Set<String> packageNames, int userId) { + mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED, + userId, 0, packageNames).sendToTarget(); + } + } + + private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) { + synchronized (mUidRulesFirstLock) { + final Set<Integer> newRestrictedUids = new ArraySet<>(); + for (String packageName : packageNames) { + final int uid = getUidForPackage(packageName, userId); + if (uid >= 0) { + newRestrictedUids.add(uid); + } + } + final Set<Integer> oldRestrictedUids = mMeteredRestrictedUids.get(userId); + mMeteredRestrictedUids.put(userId, newRestrictedUids); + handleRestrictedPackagesChangeUL(oldRestrictedUids, newRestrictedUids); + mLogger.meteredRestrictedPkgsChanged(newRestrictedUids); + } + } + + private int getUidForPackage(String packageName, int userId) { + try { + return mContext.getPackageManager().getPackageUidAsUser(packageName, + PackageManager.MATCH_KNOWN_PACKAGES, userId); + } catch (NameNotFoundException e) { + return -1; + } } private int parseSubId(NetworkState state) { @@ -4642,6 +4710,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void handleRestrictedPackagesChangeUL(Set<Integer> oldRestrictedUids, + Set<Integer> newRestrictedUids) { + if (oldRestrictedUids == null) { + for (int uid : newRestrictedUids) { + updateRulesForDataUsageRestrictionsUL(uid); + } + return; + } + for (int uid : oldRestrictedUids) { + if (!newRestrictedUids.contains(uid)) { + updateRulesForDataUsageRestrictionsUL(uid); + } + } + for (int uid : newRestrictedUids) { + if (!oldRestrictedUids.contains(uid)) { + updateRulesForDataUsageRestrictionsUL(uid); + } + } + } + + private boolean isRestrictedByAdminUL(int uid) { + final Set<Integer> restrictedUids = mMeteredRestrictedUids.get( + UserHandle.getUserId(uid)); + return restrictedUids != null && restrictedUids.contains(uid); + } + private static boolean hasRule(int uidRules, int rule) { return (uidRules & rule) != 0; } diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 253d4f5b22bb..321af43d9c3d 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -169,8 +169,9 @@ final class OverlayManagerServiceImpl { } final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId); - updateAllOverlaysForTarget(packageName, userId, targetPackage); - mListener.onOverlaysChanged(packageName, userId); + if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageChanged(@NonNull final String packageName, final int userId) { @@ -210,7 +211,9 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, null); + if (updateAllOverlaysForTarget(packageName, userId, null)) { + mListener.onOverlaysChanged(packageName, userId); + } } /** diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index c059b3784743..7d00423a2c41 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -230,7 +230,7 @@ final class OverlayManagerSettings { } mItems.remove(moveIdx); - final int newParentIdx = select(newParentPackageName, userId); + final int newParentIdx = select(newParentPackageName, userId) + 1; mItems.add(newParentIdx, itemToMove); return moveIdx != newParentIdx; } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 1717b3d1a5f7..14995b3827e1 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -560,7 +560,6 @@ public class LauncherAppsService extends SystemService { private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, @NonNull String publisherPackage, Bundle startActivityOptions, int userId) { final int code; - final long ident = injectClearCallingIdentity(); try { code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage, userId, intents, startActivityOptions); @@ -575,8 +574,6 @@ public class LauncherAppsService extends SystemService { Slog.d(TAG, "SecurityException while launching intent", e); } return false; - } finally { - injectRestoreCallingIdentity(ident); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index faf6114237cd..da1bdc7bb15a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5421,13 +5421,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - s1 = ((SharedUserSetting)obj).signatures.mSignatures; + s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - s1 = ps.signatures.mSignatures; + s1 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } @@ -5440,13 +5440,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - s2 = ((SharedUserSetting)obj).signatures.mSignatures; + s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - s2 = ps.signatures.mSignatures; + s2 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } @@ -8233,19 +8233,15 @@ Slog.e("TODD", && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { - if (ps.signatures.mSignatures != null - && ps.signatures.mSignatures.length != 0 - && ps.signatures.mSignatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { + if (ps.signatures.mSigningDetails.signatures != null + && ps.signatures.mSigningDetails.signatures.length != 0 + && ps.signatures.mSigningDetails.signatureSchemeVersion + != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. - try { - pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSignatures, - ps.signatures.mSignatureSchemeVersion); - return; - } catch (CertificateException e) { - Slog.e(TAG, "Attempt to read public keys from persisted signatures failed for " - + ps.name, e); - } + pkg.mSigningDetails = + new PackageParser.SigningDetails(ps.signatures.mSigningDetails); + return; } Slog.w(TAG, "PackageSetting for " + ps.name @@ -8573,8 +8569,9 @@ Slog.e("TODD", if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { // if the signatures don't match, wipe the installed application and its data - if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures) - != PackageManager.SIGNATURE_MATCH) { + if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, + pkg.mSigningDetails.signatures) + != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.WARN, "System package signature mismatch;" + " name: " + pkgSetting.name); @@ -9936,14 +9933,14 @@ Slog.e("TODD", if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. - pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; + pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); } else { - pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; + pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); @@ -9963,21 +9960,22 @@ Slog.e("TODD", } // We just determined the app is signed correctly, so bring // over the latest parsed certs. - pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; + pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } catch (PackageManagerException e) { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw e; } // The signature has changed, but this package is in the system // image... let's recover! - pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; + pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; // However... if this package is part of a shared user, but it // doesn't match the signature of the shared user, let's fail. // What this means is that you can't change the signatures // associated with an overall shared user, which doesn't seem all // that unreasonable. if (signatureCheckPs.sharedUser != null) { - if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures, + if (compareSignatures( + signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new PackageManagerException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, @@ -10804,9 +10802,12 @@ Slog.e("TODD", if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); - if ((platformPkgSetting.signatures.mSignatures != null) && - (compareSignatures(platformPkgSetting.signatures.mSignatures, - pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { + if ((platformPkgSetting.signatures.mSigningDetails + != PackageParser.SigningDetails.UNKNOWN) + && (compareSignatures( + platformPkgSetting.signatures.mSigningDetails.signatures, + pkg.mSigningDetails.signatures) + != PackageManager.SIGNATURE_MATCH)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.packageName + " shares privileged user " + @@ -14248,9 +14249,10 @@ Slog.e("TODD", Object obj = mSettings.getUserIdLPr(callingUid); if (obj != null) { if (obj instanceof SharedUserSetting) { - callerSignature = ((SharedUserSetting)obj).signatures.mSignatures; + callerSignature = + ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { - callerSignature = ((PackageSetting)obj).signatures.mSignatures; + callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures; } else { throw new SecurityException("Bad object " + obj + " for uid " + callingUid); } @@ -14262,7 +14264,7 @@ Slog.e("TODD", // not signed with the same cert as the caller. if (installerPackageSetting != null) { if (compareSignatures(callerSignature, - installerPackageSetting.signatures.mSignatures) + installerPackageSetting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as new installer package " @@ -14279,7 +14281,7 @@ Slog.e("TODD", // okay to change it. if (setting != null) { if (compareSignatures(callerSignature, - setting.signatures.mSignatures) + setting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as old installer package " @@ -16787,7 +16789,8 @@ Slog.e("TODD", sourcePackageSetting, scanFlags))) { sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); } else { - sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures, + sigsOk = compareSignatures( + sourcePackageSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH; } if (!sigsOk) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 7b96ca67d38f..cfc12de02267 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -509,7 +509,7 @@ public class PackageManagerServiceUtils { private static boolean matchSignaturesCompat(String packageName, PackageSignatures packageSignatures, PackageParser.SigningDetails parsedSignatures) { ArraySet<Signature> existingSet = new ArraySet<Signature>(); - for (Signature sig : packageSignatures.mSignatures) { + for (Signature sig : packageSignatures.mSigningDetails.signatures) { existingSet.add(sig); } ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>(); @@ -526,7 +526,7 @@ public class PackageManagerServiceUtils { // make sure the expanded scanned set contains all signatures in the existing one if (scannedCompatSet.equals(existingSet)) { // migrate the old signatures to the new scheme - packageSignatures.assignSignatures(parsedSignatures); + packageSignatures.mSigningDetails = parsedSignatures; return true; } return false; @@ -561,8 +561,8 @@ public class PackageManagerServiceUtils { try { PackageParser.collectCertificates(disabledPkgSetting.pkg, PackageParser.PARSE_IS_SYSTEM_DIR); - if (compareSignatures(pkgSetting.signatures.mSignatures, - disabledPkgSetting.signatures.mSignatures) + if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, + disabledPkgSetting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " + pkgSetting.name); @@ -593,9 +593,9 @@ public class PackageManagerServiceUtils { throws PackageManagerException { final String packageName = pkgSetting.name; boolean compatMatch = false; - if (pkgSetting.signatures.mSignatures != null) { + if (pkgSetting.signatures.mSigningDetails.signatures != null) { // Already existing package. Make sure signatures match - boolean match = compareSignatures(pkgSetting.signatures.mSignatures, + boolean match = compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH; if (!match && compareCompat) { @@ -605,7 +605,7 @@ public class PackageManagerServiceUtils { } if (!match && compareRecover) { match = matchSignaturesRecover( - packageName, pkgSetting.signatures.mSignatures, + packageName, pkgSetting.signatures.mSigningDetails.signatures, parsedSignatures.signatures); } @@ -620,17 +620,21 @@ public class PackageManagerServiceUtils { } } // Check for shared user signatures - if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) { + if (pkgSetting.sharedUser != null + && pkgSetting.sharedUser.signatures.mSigningDetails.signatures != null) { // Already existing package. Make sure signatures match - boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, - parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH; + boolean match = + compareSignatures( + pkgSetting.sharedUser.signatures.mSigningDetails.signatures, + parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH; if (!match && compareCompat) { match = matchSignaturesCompat( packageName, pkgSetting.sharedUser.signatures, parsedSignatures); } if (!match && compareRecover) { match = matchSignaturesRecover(packageName, - pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures.signatures); + pkgSetting.sharedUser.signatures.mSigningDetails.signatures, + parsedSignatures.signatures); compatMatch |= match; } if (!match) { diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index e3c4c4358e10..18356c570d01 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -233,7 +233,7 @@ public abstract class PackageSettingBase extends SettingBase { } public Signature[] getSignatures() { - return signatures.mSignatures; + return signatures.mSigningDetails.signatures; } /** diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java index d567d5c11cb2..d471fc837334 100644 --- a/services/core/java/com/android/server/pm/PackageSignatures.java +++ b/services/core/java/com/android/server/pm/PackageSignatures.java @@ -22,91 +22,148 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.annotation.NonNull; import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.Signature; import android.util.Log; import java.io.IOException; +import java.security.cert.CertificateException; import java.util.ArrayList; class PackageSignatures { - Signature[] mSignatures; - @SignatureSchemeVersion int mSignatureSchemeVersion; + + @NonNull PackageParser.SigningDetails mSigningDetails; PackageSignatures(PackageSignatures orig) { - if (orig != null && orig.mSignatures != null) { - mSignatures = orig.mSignatures.clone(); - mSignatureSchemeVersion = orig.mSignatureSchemeVersion; + if (orig != null && orig.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) { + mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails); + } else { + mSigningDetails = PackageParser.SigningDetails.UNKNOWN; } } PackageSignatures(PackageParser.SigningDetails signingDetails) { - assignSignatures(signingDetails); + mSigningDetails = signingDetails; } PackageSignatures() { + mSigningDetails = PackageParser.SigningDetails.UNKNOWN; } void writeXml(XmlSerializer serializer, String tagName, - ArrayList<Signature> pastSignatures) throws IOException { - if (mSignatures == null) { + ArrayList<Signature> writtenSignatures) throws IOException { + if (mSigningDetails.signatures == null) { return; } serializer.startTag(null, tagName); - serializer.attribute(null, "count", - Integer.toString(mSignatures.length)); - serializer.attribute(null, "schemeVersion", Integer.toString(mSignatureSchemeVersion)); - for (int i=0; i<mSignatures.length; i++) { + serializer.attribute(null, "count", Integer.toString(mSigningDetails.signatures.length)); + serializer.attribute(null, "schemeVersion", + Integer.toString(mSigningDetails.signatureSchemeVersion)); + writeCertsListXml(serializer, writtenSignatures, mSigningDetails.signatures, null); + + // if we have past signer certificate information, write it out + if (mSigningDetails.pastSigningCertificates != null) { + serializer.startTag(null, "pastSigs"); + serializer.attribute(null, "count", + Integer.toString(mSigningDetails.pastSigningCertificates.length)); + writeCertsListXml( + serializer, writtenSignatures, mSigningDetails.pastSigningCertificates, + mSigningDetails.pastSigningCertificatesFlags); + serializer.endTag(null, "pastSigs"); + } + serializer.endTag(null, tagName); + } + + private void writeCertsListXml(XmlSerializer serializer, ArrayList<Signature> writtenSignatures, + Signature[] signatures, int[] flags) throws IOException { + for (int i=0; i<signatures.length; i++) { serializer.startTag(null, "cert"); - final Signature sig = mSignatures[i]; + final Signature sig = signatures[i]; final int sigHash = sig.hashCode(); - final int numPast = pastSignatures.size(); + final int numWritten = writtenSignatures.size(); int j; - for (j=0; j<numPast; j++) { - Signature pastSig = pastSignatures.get(j); - if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) { + for (j=0; j<numWritten; j++) { + Signature writtenSig = writtenSignatures.get(j); + if (writtenSig.hashCode() == sigHash && writtenSig.equals(sig)) { serializer.attribute(null, "index", Integer.toString(j)); break; } } - if (j >= numPast) { - pastSignatures.add(sig); - serializer.attribute(null, "index", Integer.toString(numPast)); + if (j >= numWritten) { + writtenSignatures.add(sig); + serializer.attribute(null, "index", Integer.toString(numWritten)); serializer.attribute(null, "key", sig.toCharsString()); } + if (flags != null) { + serializer.attribute(null, "flags", Integer.toString(flags[i])); + } serializer.endTag(null, "cert"); } - serializer.endTag(null, tagName); } - void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures) + void readXml(XmlPullParser parser, ArrayList<Signature> readSignatures) throws IOException, XmlPullParserException { + PackageParser.SigningDetails.Builder builder = + new PackageParser.SigningDetails.Builder(); + String countStr = parser.getAttributeValue(null, "count"); if (countStr == null) { PackageManagerService.reportSettingsProblem(Log.WARN, - "Error in package manager settings: <signatures> has" + "Error in package manager settings: <sigs> has" + " no count at " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); } + final int count = Integer.parseInt(countStr); + String schemeVersionStr = parser.getAttributeValue(null, "schemeVersion"); + int signatureSchemeVersion; if (schemeVersionStr == null) { PackageManagerService.reportSettingsProblem(Log.WARN, - "Error in package manager settings: <signatures> has no schemeVersion at " + "Error in package manager settings: <sigs> has no schemeVersion at " + parser.getPositionDescription()); - mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; + signatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; } else { - mSignatureSchemeVersion = Integer.parseInt(countStr); + signatureSchemeVersion = Integer.parseInt(schemeVersionStr); } - final int count = Integer.parseInt(countStr); - mSignatures = new Signature[count]; + builder.setSignatureSchemeVersion(signatureSchemeVersion); + Signature[] signatures = new Signature[count]; + int pos = readCertsListXml(parser, readSignatures, signatures, null, builder); + builder.setSignatures(signatures); + if (pos < count) { + // Should never happen -- there is an error in the written + // settings -- but if it does we don't want to generate + // a bad array. + Signature[] newSigs = new Signature[pos]; + System.arraycopy(signatures, 0, newSigs, 0, pos); + builder = builder.setSignatures(newSigs); + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <sigs> count does not match number of " + + " <cert> entries" + parser.getPositionDescription()); + } + + try { + mSigningDetails = builder.build(); + } catch (CertificateException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <sigs> " + + "unable to convert certificate(s) to public key(s)."); + mSigningDetails = PackageParser.SigningDetails.UNKNOWN; + } + } + + private int readCertsListXml(XmlPullParser parser, ArrayList<Signature> readSignatures, + Signature[] signatures, int[] flags, PackageParser.SigningDetails.Builder builder) + throws IOException, XmlPullParserException { + int count = signatures.length; int pos = 0; int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; @@ -121,83 +178,128 @@ class PackageSignatures { int idx = Integer.parseInt(index); String key = parser.getAttributeValue(null, "key"); if (key == null) { - if (idx >= 0 && idx < pastSignatures.size()) { - Signature sig = pastSignatures.get(idx); + if (idx >= 0 && idx < readSignatures.size()) { + Signature sig = readSignatures.get(idx); if (sig != null) { - mSignatures[pos] = pastSignatures.get(idx); + signatures[pos] = readSignatures.get(idx); pos++; } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <cert> " - + "index " + index + " is not defined at " - + parser.getPositionDescription()); + + "index " + index + " is not defined at " + + parser.getPositionDescription()); } } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <cert> " - + "index " + index + " is out of bounds at " - + parser.getPositionDescription()); + + "index " + index + " is out of bounds at " + + parser.getPositionDescription()); } } else { - while (pastSignatures.size() <= idx) { - pastSignatures.add(null); + while (readSignatures.size() <= idx) { + readSignatures.add(null); } Signature sig = new Signature(key); - pastSignatures.set(idx, sig); - mSignatures[pos] = sig; + readSignatures.set(idx, sig); + signatures[pos] = sig; pos++; } } catch (NumberFormatException e) { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <cert> " - + "index " + index + " is not a number at " - + parser.getPositionDescription()); + + "index " + index + " is not a number at " + + parser.getPositionDescription()); } catch (IllegalArgumentException e) { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <cert> " - + "index " + index + " has an invalid signature at " - + parser.getPositionDescription() + ": " - + e.getMessage()); + + "index " + index + " has an invalid signature at " + + parser.getPositionDescription() + ": " + + e.getMessage()); + } + + if (flags != null) { + String flagsStr = parser.getAttributeValue(null, "flags"); + if (flagsStr != null) { + try { + flags[pos] = Integer.parseInt(flagsStr); + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> " + + "flags " + flagsStr + " is not a number at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <cert> has no" + + " flags at " + parser.getPositionDescription()); + } } } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <cert> has" - + " no index at " + parser.getPositionDescription()); + + " no index at " + parser.getPositionDescription()); } } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: too " - + "many <cert> tags, expected " + count - + " at " + parser.getPositionDescription()); + + "many <cert> tags, expected " + count + + " at " + parser.getPositionDescription()); + } + } else if (tagName.equals("pastSigs")) { + if (flags == null) { + // we haven't encountered pastSigs yet, go ahead + String countStr = parser.getAttributeValue(null, "count"); + if (countStr == null) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <pastSigs> has" + + " no count at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } + try { + final int pastSigsCount = Integer.parseInt(countStr); + Signature[] pastSignatures = new Signature[pastSigsCount]; + int[] pastSignaturesFlags = new int[pastSigsCount]; + int pastSigsPos = readCertsListXml(parser, readSignatures, pastSignatures, + pastSignaturesFlags, builder); + builder = builder + .setPastSigningCertificates(pastSignatures) + .setPastSigningCertificatesFlags(pastSignaturesFlags); + + if (pastSigsPos < pastSigsCount) { + // Should never happen -- there is an error in the written + // settings -- but if it does we don't want to generate + // a bad array. + Signature[] newSigs = new Signature[pastSigsPos]; + System.arraycopy(pastSignatures, 0, newSigs, 0, pastSigsPos); + int[] newFlags = new int[pastSigsPos]; + System.arraycopy(pastSignaturesFlags, 0, newFlags, 0, pastSigsPos); + builder = builder + .setPastSigningCertificates(newSigs) + .setPastSigningCertificatesFlags(newFlags); + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <pastSigs> count does not " + + "match number of <cert> entries " + + parser.getPositionDescription()); + } + } catch (NumberFormatException e) { + PackageManagerService.reportSettingsProblem(Log.WARN, + "Error in package manager settings: <pastSigs> " + + "count " + countStr + " is not a number at " + + parser.getPositionDescription()); + } + } else { + PackageManagerService.reportSettingsProblem(Log.WARN, + "<pastSigs> encountered multiple times under the same <sigs> at " + + parser.getPositionDescription()); } } else { PackageManagerService.reportSettingsProblem(Log.WARN, - "Unknown element under <cert>: " - + parser.getName()); + "Unknown element under <sigs>: " + + parser.getName()); } XmlUtils.skipCurrentTag(parser); } - - if (pos < count) { - // Should never happen -- there is an error in the written - // settings -- but if it does we don't want to generate - // a bad array. - Signature[] newSigs = new Signature[pos]; - System.arraycopy(mSignatures, 0, newSigs, 0, pos); - mSignatures = newSigs; - } - } - - void assignSignatures(PackageParser.SigningDetails signingDetails) { - mSignatureSchemeVersion = signingDetails.signatureSchemeVersion; - if (!signingDetails.hasSignatures()) { - mSignatures = null; - return; - } - mSignatures = new Signature[signingDetails.signatures.length]; - for (int i=0; i<signingDetails.signatures.length; i++) { - mSignatures[i] = signingDetails.signatures[i]; - } + return pos; } @Override @@ -206,16 +308,26 @@ class PackageSignatures { buf.append("PackageSignatures{"); buf.append(Integer.toHexString(System.identityHashCode(this))); buf.append(" version:"); - buf.append(mSignatureSchemeVersion); + buf.append(mSigningDetails.signatureSchemeVersion); buf.append(", signatures:["); - if (mSignatures != null) { - for (int i=0; i<mSignatures.length; i++) { + if (mSigningDetails.signatures != null) { + for (int i = 0; i < mSigningDetails.signatures.length; i++) { if (i > 0) buf.append(", "); buf.append(Integer.toHexString( - mSignatures[i].hashCode())); + mSigningDetails.signatures[i].hashCode())); } } buf.append("]}"); + buf.append(", past signatures:["); + if (mSigningDetails.pastSigningCertificates != null) { + for (int i = 0; i < mSigningDetails.pastSigningCertificates.length; i++) { + if (i > 0) buf.append(", "); + buf.append(Integer.toHexString( + mSigningDetails.pastSigningCertificates[i].hashCode())); + buf.append(" flags: "); + buf.append(Integer.toHexString(mSigningDetails.pastSigningCertificatesFlags[i])); + } + } return buf.toString(); } }
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index ecbc45217dbb..8ce412e5783a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -920,13 +920,13 @@ public final class Settings { // by that time. void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) { // Update signatures if needed. - if (p.signatures.mSignatures == null) { - p.signatures.assignSignatures(pkg.mSigningDetails); + if (p.signatures.mSigningDetails.signatures == null) { + p.signatures.mSigningDetails = pkg.mSigningDetails; } // If this app defines a shared user id initialize // the shared user signatures as well. - if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { - p.sharedUser.signatures.assignSignatures(pkg.mSigningDetails); + if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) { + p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails; } addPackageSettingLPw(p, p.sharedUser); } diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java index 30fc63c2a1b0..be9b204721db 100644 --- a/services/core/java/com/android/server/timezone/RulesManagerService.java +++ b/services/core/java/com/android/server/timezone/RulesManagerService.java @@ -143,6 +143,26 @@ public final class RulesManagerService extends IRulesManager.Stub { return null; } + // Determine the installed distro state. This should be possible regardless of whether + // there's an operation in progress. + DistroVersion installedDistroVersion; + int distroStatus = DISTRO_STATUS_UNKNOWN; + DistroRulesVersion installedDistroRulesVersion = null; + try { + installedDistroVersion = mInstaller.getInstalledDistroVersion(); + if (installedDistroVersion == null) { + distroStatus = DISTRO_STATUS_NONE; + installedDistroRulesVersion = null; + } else { + distroStatus = DISTRO_STATUS_INSTALLED; + installedDistroRulesVersion = new DistroRulesVersion( + installedDistroVersion.rulesVersion, + installedDistroVersion.revision); + } + } catch (DistroException | IOException e) { + Slog.w(TAG, "Failed to read installed distro.", e); + } + boolean operationInProgress = this.mOperationInProgress.get(); // Determine the staged operation status, if possible. @@ -168,27 +188,6 @@ public final class RulesManagerService extends IRulesManager.Stub { Slog.w(TAG, "Failed to read staged distro.", e); } } - - // Determine the installed distro state, if possible. - DistroVersion installedDistroVersion; - int distroStatus = DISTRO_STATUS_UNKNOWN; - DistroRulesVersion installedDistroRulesVersion = null; - if (!operationInProgress) { - try { - installedDistroVersion = mInstaller.getInstalledDistroVersion(); - if (installedDistroVersion == null) { - distroStatus = DISTRO_STATUS_NONE; - installedDistroRulesVersion = null; - } else { - distroStatus = DISTRO_STATUS_INSTALLED; - installedDistroRulesVersion = new DistroRulesVersion( - installedDistroVersion.rulesVersion, - installedDistroVersion.revision); - } - } catch (DistroException | IOException e) { - Slog.w(TAG, "Failed to read installed distro.", e); - } - } return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED, operationInProgress, stagedOperationStatus, stagedDistroRulesVersion, distroStatus, installedDistroRulesVersion); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 7a0b1bf46fcf..4f2866bd8363 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -26,6 +26,7 @@ import android.security.keystore.ParcelableKeyGenParameterSpec; import com.android.internal.R; import com.android.server.SystemService; +import java.util.ArrayList; import java.util.List; /** @@ -135,4 +136,14 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public CharSequence getPrintingDisabledReason() { return null; } + + @Override + public List<String> setMeteredDataDisabled(ComponentName admin, List<String> packageNames) { + return packageNames; + } + + @Override + public List<String> getMeteredDataDisabled(ComponentName admin) { + return new ArrayList<>(); + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6bee9d67f215..4d6989badda8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -806,6 +806,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TAG_MANDATORY_BACKUP_TRANSPORT = "mandatory_backup_transport"; private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message"; private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message"; + private static final String TAG_METERED_DATA_DISABLED_PACKAGES + = "metered_data_disabled_packages"; DeviceAdminInfo info; @@ -872,6 +874,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + // The list of packages which are not allowed to use metered data. + List<String> meteredDisabledPackages; + final Set<String> accountTypesWithManagementDisabled = new ArraySet<>(); // The list of permitted accessibility services package namesas set by a profile @@ -1153,6 +1158,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS, permittedNotificationListeners); writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); + writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages); if (hasUserRestrictions()) { UserRestrictionsUtils.writeRestrictions( out, userRestrictions, TAG_USER_RESTRICTIONS); @@ -1349,6 +1355,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { permittedNotificationListeners = readPackageList(parser, tag); } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { keepUninstalledPackages = readPackageList(parser, tag); + } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) { + meteredDisabledPackages = readPackageList(parser, tag); } else if (TAG_USER_RESTRICTIONS.equals(tag)) { userRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) { @@ -1647,6 +1655,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policy.mAdminList.remove(i); policy.mAdminMap.remove(aa.info.getComponent()); pushActiveAdminPackagesLocked(userHandle); + pushMeteredDisabledPackagesLocked(userHandle); } } } catch (RemoteException re) { @@ -3502,6 +3511,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mInjector.postOnSystemServerInitThreadPool(() -> { pushActiveAdminPackages(); mUsageStatsManagerInternal.onAdminDataAvailable(); + pushAllMeteredRestrictedPackages(); mInjector.getNetworkPolicyManagerInternal().onAdminDataAvailable(); }); } @@ -3517,6 +3527,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private void pushAllMeteredRestrictedPackages() { + synchronized (this) { + final List<UserInfo> users = mUserManager.getUsers(); + for (int i = users.size() - 1; i >= 0; --i) { + final int userId = users.get(i).id; + mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackagesAsync( + getMeteredDisabledPackagesLocked(userId), userId); + } + } + } + private void pushActiveAdminPackagesLocked(int userId) { mUsageStatsManagerInternal.setActiveAdminApps( getActiveAdminPackagesLocked(userId), userId); @@ -11031,6 +11052,93 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public List<String> setMeteredDataDisabled(ComponentName who, List<String> packageNames) { + Preconditions.checkNotNull(who); + Preconditions.checkNotNull(packageNames); + + if (!mHasFeature) { + return packageNames; + } + synchronized (this) { + final ActiveAdmin admin = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + final int callingUserId = mInjector.userHandleGetCallingUserId(); + final long identity = mInjector.binderClearCallingIdentity(); + try { + final List<String> excludedPkgs + = removeInvalidPkgsForMeteredDataRestriction(callingUserId, packageNames); + admin.meteredDisabledPackages = packageNames; + pushMeteredDisabledPackagesLocked(callingUserId); + saveSettingsLocked(callingUserId); + return excludedPkgs; + } finally { + mInjector.binderRestoreCallingIdentity(identity); + } + } + } + + private List<String> removeInvalidPkgsForMeteredDataRestriction( + int userId, List<String> pkgNames) { + final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId); + final List<String> excludedPkgs = new ArrayList<>(); + for (int i = pkgNames.size() - 1; i >= 0; --i) { + final String pkgName = pkgNames.get(i); + // If the package is an active admin, don't restrict it. + if (activeAdmins.contains(pkgName)) { + excludedPkgs.add(pkgName); + continue; + } + // If the package doesn't exist, don't restrict it. + try { + if (!mInjector.getIPackageManager().isPackageAvailable(pkgName, userId)) { + excludedPkgs.add(pkgName); + } + } catch (RemoteException e) { + // Should not happen + } + } + pkgNames.removeAll(excludedPkgs); + return excludedPkgs; + } + + @Override + public List<String> getMeteredDataDisabled(ComponentName who) { + Preconditions.checkNotNull(who); + + if (!mHasFeature) { + return new ArrayList<>(); + } + synchronized (this) { + final ActiveAdmin admin = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + return admin.meteredDisabledPackages == null + ? new ArrayList<>() : admin.meteredDisabledPackages; + } + } + + private void pushMeteredDisabledPackagesLocked(int userId) { + mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages( + getMeteredDisabledPackagesLocked(userId), userId); + } + + private Set<String> getMeteredDisabledPackagesLocked(int userId) { + final DevicePolicyData policy = getUserData(userId); + final Set<String> restrictedPkgs = new ArraySet<>(); + for (int i = policy.mAdminList.size() - 1; i >= 0; --i) { + final ActiveAdmin admin = policy.mAdminList.get(i); + if (!isActiveAdminWithPolicyForUserLocked(admin, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, userId)) { + // Not a profile or device owner, ignore + continue; + } + if (admin.meteredDisabledPackages != null) { + restrictedPkgs.addAll(admin.meteredDisabledPackages); + } + } + return restrictedPkgs; + } + + @Override public void setAffiliationIds(ComponentName admin, List<String> ids) { if (!mHasFeature) { return; @@ -11389,6 +11497,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { resetGlobalProxyLocked(policy); } pushActiveAdminPackagesLocked(userHandle); + pushMeteredDisabledPackagesLocked(userHandle); saveSettingsLocked(userHandle); updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index 589a89bcbddf..b58c7003f39e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -228,8 +228,8 @@ public class ActivityStarterTests extends ActivityTestsBase { if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) { doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission( - any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), anyBoolean(), - any(), any(), any(), any()); + any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), + anyBoolean(), any(), any(), any()); } try { @@ -278,7 +278,7 @@ public class ActivityStarterTests extends ActivityTestsBase { .setResultTo(resultTo) .setRequestCode(requestCode) .setReason("testLaunchActivityPermissionDenied") - .setActivityOptions(options) + .setActivityOptions(new SafeActivityOptions(options)) .execute(); verify(options, times(1)).abort(); } diff --git a/services/tests/servicestests/src/com/android/server/am/SafeActivityOptionsTest.java b/services/tests/servicestests/src/com/android/server/am/SafeActivityOptionsTest.java new file mode 100644 index 000000000000..168bc1782d56 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/SafeActivityOptionsTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.am; + +import static org.junit.Assert.assertEquals; + +import android.app.ActivityOptions; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@Presubmit +@FlakyTest +@RunWith(AndroidJUnit4.class) +public class SafeActivityOptionsTest { + + @Test + public void testMerge() { + final ActivityOptions opts1 = ActivityOptions.makeBasic(); + opts1.setLaunchDisplayId(5); + final ActivityOptions opts2 = ActivityOptions.makeBasic(); + opts2.setLaunchDisplayId(6); + final SafeActivityOptions options = new SafeActivityOptions(opts1); + final ActivityOptions result = options.mergeActivityOptions(opts1, opts2); + assertEquals(6, result.getLaunchDisplayId()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java index 9cac536bead6..613d0afea183 100644 --- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java +++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java @@ -87,6 +87,11 @@ public class PackageManagerStub extends PackageManager { } @Override + public Intent getCarLaunchIntentForPackage(String packageName) { + return null; + } + + @Override public int[] getPackageGids(String packageName) throws NameNotFoundException { return new int[0]; } 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 725ede81754a..e8d6ed28ed29 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -126,6 +126,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL); public static final String NOT_DEVICE_OWNER_MSG = "does not own the device"; + public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile"; public static final String ONGOING_CALL_MSG = "ongoing call on the device"; // TODO replace all instances of this with explicit {@link #mServiceContext}. @@ -301,10 +302,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Verify verify(getServices().usageStatsManagerInternal).setActiveAdminApps( - MockUtils.checkAdminApps(admin1.getPackageName()), + MockUtils.checkApps(admin1.getPackageName()), eq(UserHandle.USER_SYSTEM)); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( - MockUtils.checkAdminApps(admin2.getPackageName(), + MockUtils.checkApps(admin2.getPackageName(), adminAnotherPackage.getPackageName()), eq(DpmMockContext.CALLER_USER_HANDLE)); verify(getServices().usageStatsManagerInternal).onAdminDataAvailable(); @@ -705,7 +706,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE)); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( - MockUtils.checkAdminApps(admin2.getPackageName()), + MockUtils.checkApps(admin2.getPackageName()), eq(DpmMockContext.CALLER_USER_HANDLE)); // Again broadcast from saveSettingsLocked(). @@ -1360,6 +1361,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(packageName), anyInt(), eq(userId)); + doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId); // Setup application UID with the PackageManager doReturn(uid).when(getServices().packageManager).getPackageUidAsUser( eq(packageName), @@ -2101,6 +2103,53 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } + public void testSetGetMeteredDataDisabled() throws Exception { + setAsProfileOwner(admin1); + + final ArrayList<String> emptyList = new ArrayList<>(); + assertEquals(emptyList, dpm.getMeteredDataDisabled(admin1)); + + // Setup + final ArrayList<String> pkgsToRestrict = new ArrayList<>(); + final String package1 = "com.example.one"; + final String package2 = "com.example.two"; + pkgsToRestrict.add(package1); + pkgsToRestrict.add(package2); + setupPackageInPackageManager(package1, DpmMockContext.CALLER_USER_HANDLE, 123, 0); + setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0); + List<String> excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict); + + // Verify + assertEquals(emptyList, excludedPkgs); + assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1)); + verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages( + MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])), + eq(DpmMockContext.CALLER_USER_HANDLE)); + + // Setup + pkgsToRestrict.remove(package1); + excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict); + + // Verify + assertEquals(emptyList, excludedPkgs); + assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1)); + verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages( + MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])), + eq(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testSetGetMeteredDataDisabled_deviceAdmin() { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + dpm.setActiveAdmin(admin1, true); + assertTrue(dpm.isAdminActive(admin1)); + mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS); + + assertExpectException(SecurityException.class, /* messageRegex= */ NOT_PROFILE_OWNER_MSG, + () -> dpm.setMeteredDataDisabled(admin1, new ArrayList<>())); + assertExpectException(SecurityException.class, /* messageRegex= */ NOT_PROFILE_OWNER_MSG, + () -> dpm.getMeteredDataDisabled(admin1)); + } + public void testCreateAdminSupportIntent() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java index dec962eeefeb..92ea76656693 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -119,25 +119,25 @@ public class MockUtils { return MockitoHamcrest.argThat(m); } - public static Set<String> checkAdminApps(String... adminApps) { + public static Set<String> checkApps(String... adminApps) { final Matcher<Set<String>> m = new BaseMatcher<Set<String>>() { @Override public boolean matches(Object item) { if (item == null) return false; - final Set<String> actualAdminApps = (Set<String>) item; - if (adminApps.length != actualAdminApps.size()) { + final Set<String> actualApps = (Set<String>) item; + if (adminApps.length != actualApps.size()) { return false; } - final Set<String> copyOfAdmins = new ArraySet<>(actualAdminApps); + final Set<String> copyOfApps = new ArraySet<>(actualApps); for (String adminApp : adminApps) { - copyOfAdmins.remove(adminApp); + copyOfApps.remove(adminApp); } - return copyOfAdmins.isEmpty(); + return copyOfApps.isEmpty(); } @Override public void describeTo(Description description) { - description.appendText("Admin apps=" + Arrays.toString(adminApps)); + description.appendText("Apps=" + Arrays.toString(adminApps)); } }; return MockitoHamcrest.argThat(m); diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java index c5f8c90dd6c6..675000e91a1c 100644 --- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java @@ -171,6 +171,23 @@ public class PersistentDataStoreTest { newDataStore.getBrightnessConfiguration(0 /*userSerial*/)); } + @Test + public void testNullBrightnessConfiguration() { + final float[] lux = { 0f, 10f }; + final float[] nits = {1f, 100f }; + final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits) + .setDescription("a description") + .build(); + mDataStore.loadIfNeeded(); + assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); + + mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename"); + assertNotNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); + + mDataStore.setBrightnessConfigurationForUser(null, 0, "packagename"); + assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); + } + public class TestInjector extends PersistentDataStore.Injector { private InputStream mReadStream; private OutputStream mWriteStream; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 272b5d899d4b..e8648701bd0d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -31,6 +31,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; +import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; @@ -80,6 +81,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { DevicePolicyManagerInternal mDevicePolicyManagerInternal; KeyStore mKeyStore; MockSyntheticPasswordManager mSpManager; + IAuthSecret mAuthSecretService; @Override protected void setUp() throws Exception { @@ -115,17 +117,21 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { }; mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager); + mAuthSecretService = mock(IAuthSecret.class); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, - mSpManager); + mSpManager, mAuthSecretService); when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO); mPrimaryUserProfiles.add(PRIMARY_USER_INFO); installChildProfile(MANAGED_PROFILE_USER_ID); installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID); - when(mUserManager.getUsers(anyBoolean())).thenReturn(mPrimaryUserProfiles); when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserProfiles); when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO); + final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles); + allUsers.add(SECONDARY_USER_INFO); + when(mUserManager.getUsers(anyBoolean())).thenReturn(allUsers); + when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer( new Answer<Boolean>() { @Override diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java index 4ad9f19735c4..d2caa0af0ba2 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java @@ -22,6 +22,7 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.server.testutils.TestUtils.assertExpectException; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; @@ -31,6 +32,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; +import java.util.ArrayList; + +import org.mockito.ArgumentCaptor; + /** * Run the synthetic password tests with caching enabled. * @@ -88,6 +93,26 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { .getResponseCode()); } + public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { + final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password"; + final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword"; + + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + // Untrusted change password + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + + // Verify the password + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); + + // Ensure the same secret was passed each time + ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); + verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); + assertEquals(1, secret.getAllValues().stream().distinct().count()); + } + public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password"; final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword"; 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 0916a335b51e..fe683abe7e1b 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.mock; import android.app.IActivityManager; import android.content.Context; +import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.Handler; import android.os.Looper; import android.os.Process; @@ -42,10 +43,12 @@ public class LockSettingsServiceTestable extends LockSettingsService { private LockPatternUtils mLockPatternUtils; private IStorageManager mStorageManager; private SyntheticPasswordManager mSpManager; + private IAuthSecret mAuthSecretService; public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore, IActivityManager activityManager, LockPatternUtils lockPatternUtils, - IStorageManager storageManager, SyntheticPasswordManager spManager) { + IStorageManager storageManager, SyntheticPasswordManager spManager, + IAuthSecret authSecretService) { super(context); mLockSettingsStorage = storage; mKeyStore = keyStore; @@ -109,10 +112,11 @@ public class LockSettingsServiceTestable extends LockSettingsService { protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils, LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore, IStorageManager storageManager, IActivityManager mActivityManager, - SyntheticPasswordManager spManager) { + SyntheticPasswordManager spManager, IAuthSecret authSecretService) { super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils, - storageManager, spManager)); + storageManager, spManager, authSecretService)); mGateKeeperService = gatekeeper; + mAuthSecretService = authSecretService; } @Override diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index b07d6ac5dc04..294c3e99ad7e 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -24,6 +24,10 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import android.app.admin.PasswordMetrics; @@ -36,6 +40,10 @@ import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationRe import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken; import com.android.server.locksettings.SyntheticPasswordManager.PasswordData; +import java.util.ArrayList; + +import org.mockito.ArgumentCaptor; + /** * runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests @@ -169,6 +177,46 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } + public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException { + final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password"; + final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new"; + + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD, + PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); + + // Check the same secret was passed each time + ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); + verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); + assertEquals(1, secret.getAllValues().stream().distinct().count()); + } + + public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException { + final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password"; + final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new"; + + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + reset(mAuthSecretService); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); + verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class)); + } + + public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException { + final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password"; + final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new"; + + initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID) + .getResponseCode()); + verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); + } + public void testManagedProfileUnifiedChallengeMigration() throws RemoteException { final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd"; disableSyntheticPassword(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 7eec4fea64dc..6edaf87e135f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -16,11 +16,11 @@ package com.android.server.locksettings.recoverablekeystore; -import static android.security.keystore.KeychainProtectionParams.TYPE_LOCKSCREEN; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN; -import static android.security.keystore.KeychainProtectionParams.TYPE_PASSWORD; -import static android.security.keystore.KeychainProtectionParams.TYPE_PATTERN; -import static android.security.keystore.KeychainProtectionParams.TYPE_PIN; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PASSWORD; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PATTERN; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; @@ -40,9 +40,9 @@ import android.content.Context; import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.security.keystore.KeyDerivationParams; -import android.security.keystore.KeychainSnapshot; -import android.security.keystore.WrappedApplicationKey; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.KeychainSnapshot; +import android.security.keystore.recovery.WrappedApplicationKey; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index 970bc33337da..a3a2e4764edc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -16,8 +16,8 @@ package com.android.server.locksettings.recoverablekeystore; -import static android.security.keystore.KeychainProtectionParams.TYPE_LOCKSCREEN; -import static android.security.keystore.KeychainProtectionParams.TYPE_PASSWORD; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_LOCKSCREEN; +import static android.security.keystore.recovery.KeychainProtectionParams.TYPE_PASSWORD; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; @@ -42,9 +42,9 @@ import android.os.UserHandle; import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; -import android.security.keystore.KeyDerivationParams; -import android.security.keystore.KeychainProtectionParams; -import android.security.keystore.WrappedApplicationKey; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.KeychainProtectionParams; +import android.security.keystore.recovery.WrappedApplicationKey; import android.support.test.filters.SmallTest; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java index 56b44e2fa17c..89c5c6c8a072 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java @@ -3,7 +3,7 @@ package com.android.server.locksettings.recoverablekeystore.storage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import android.security.keystore.KeychainSnapshot; +import android.security.keystore.recovery.KeychainSnapshot; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index 49601c32cdc2..5c7348c68240 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -497,7 +497,9 @@ public class PackageParserTest { new PackageParser.SigningDetails( new Signature[] { new Signature(new byte[16]) }, 2, - new ArraySet<>()); + new ArraySet<>(), + null, + null); pkg.mExtras = new Bundle(); pkg.mRestrictedAccountType = "foo19"; pkg.mRequiredAccountType = "foo20"; diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java index d09d0c8d9e5c..1cfae1ef1a6d 100644 --- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java @@ -289,11 +289,13 @@ public class RulesManagerServiceTest { // Request the rules state while the async operation is "happening". RulesState actualRulesState = mRulesManagerService.getRulesState(); + DistroRulesVersion expectedInstalledDistroRulesVersion = + new DistroRulesVersion(installedRulesVersion, revision); RulesState expectedRuleState = new RulesState( systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, true /* operationInProgress */, RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */, - RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */); + RulesState.DISTRO_STATUS_INSTALLED, expectedInstalledDistroRulesVersion); assertEquals(expectedRuleState, actualRulesState); } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java index f8db4faaa81f..794d0336904a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java @@ -54,7 +54,7 @@ public class WindowAnimationSpecTest { @Test public void testApply_clipNone() { Rect windowCrop = new Rect(0, 0, 20, 20); - Animation a = new ClipRectAnimation(windowCrop, windowCrop); + Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); @@ -99,7 +99,8 @@ public class WindowAnimationSpecTest { public void testApply_clipBeforeNoStackBounds() { // Stack bounds is (0, 0, 0, 0) animation clip is (0, 0, 20, 20) Rect windowCrop = new Rect(0, 0, 20, 20); - Animation a = new ClipRectAnimation(windowCrop, windowCrop); + Animation a = createClipRectAnimation(windowCrop, windowCrop); + a.initialize(0, 0, 0, 0); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); @@ -110,7 +111,7 @@ public class WindowAnimationSpecTest { public void testApply_clipBeforeSmallerAnimationClip() { // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5) Rect windowCrop = new Rect(0, 0, 5, 5); - Animation a = new ClipRectAnimation(windowCrop, windowCrop); + Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); @@ -122,11 +123,17 @@ public class WindowAnimationSpecTest { public void testApply_clipBeforeSmallerStackClip() { // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 20, 20) Rect windowCrop = new Rect(0, 0, 20, 20); - Animation a = new ClipRectAnimation(windowCrop, windowCrop); + Animation a = createClipRectAnimation(windowCrop, windowCrop); WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null, mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM); windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0); verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(rect -> rect.equals(mStackBounds))); } + + private Animation createClipRectAnimation(Rect fromClip, Rect toClip) { + Animation a = new ClipRectAnimation(fromClip, toClip); + a.initialize(0, 0, 0, 0); + return a; + } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 649d4783cc7a..cbc9428bcf56 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -275,7 +275,6 @@ public class CarrierConfigManager { * * @see SubscriptionManager#getSubscriptionPlans(int) * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) - * @hide */ @SystemApi public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 57f4cf28d90d..debf43da79b4 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -462,8 +462,6 @@ public class SubscriptionManager { * <p> * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription * the user is interested in. - * - * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SystemApi @@ -481,8 +479,6 @@ public class SubscriptionManager { * <p> * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription * the user is interested in. - * - * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @SystemApi @@ -1698,7 +1694,6 @@ public class SubscriptionManager { * </ul> * * @param subId the subscriber this relationship applies to - * @hide */ @SystemApi public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) { @@ -1728,7 +1723,6 @@ public class SubscriptionManager { * @param plans the list of plans. The first plan is always the primary and * most important plan. Any additional plans are secondary and * may not be displayed or used by decision making logic. - * @hide */ @SystemApi public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { @@ -1769,7 +1763,6 @@ public class SubscriptionManager { * be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. - * @hide */ @SystemApi public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @@ -1804,7 +1797,6 @@ public class SubscriptionManager { * be automatically cleared, or {@code 0} to leave in the * requested state until explicitly cleared, or the next reboot, * whichever happens first. - * @hide */ @SystemApi public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java index 265e3e7c8a01..941165212aa7 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/telephony/java/android/telephony/SubscriptionPlan.java @@ -43,7 +43,6 @@ import java.util.Iterator; * * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) * @see SubscriptionManager#getSubscriptionPlans(int) - * @hide */ @SystemApi public final class SubscriptionPlan implements Parcelable { diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index ea0817551369..fa19ea069044 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -17,6 +17,7 @@ package android.telephony.data; import android.annotation.CallSuper; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; @@ -32,6 +33,8 @@ import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.util.SparseArray; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -56,6 +59,33 @@ public abstract class DataService extends Service { public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService"; public static final String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID"; + /** {@hide} */ + @IntDef(prefix = "REQUEST_REASON_", value = { + REQUEST_REASON_NORMAL, + REQUEST_REASON_HANDOVER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SetupDataReason {} + + /** {@hide} */ + @IntDef(prefix = "REQUEST_REASON_", value = { + REQUEST_REASON_NORMAL, + REQUEST_REASON_SHUTDOWN, + REQUEST_REASON_HANDOVER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DeactivateDataReason {} + + + /** The reason of the data request is normal */ + public static final int REQUEST_REASON_NORMAL = 1; + + /** The reason of the data request is device shutdown */ + public static final int REQUEST_REASON_SHUTDOWN = 2; + + /** The reason of the data request is IWLAN handover */ + public static final int REQUEST_REASON_HANDOVER = 3; + private static final int DATA_SERVICE_INTERNAL_REQUEST_INITIALIZE_SERVICE = 1; private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL = 2; private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL = 3; @@ -110,13 +140,14 @@ public abstract class DataService extends Service { * @param dataProfile Data profile used for data call setup. See {@link DataProfile} * @param isRoaming True if the device is data roaming. * @param allowRoaming True if data roaming is allowed by the user. - * @param isHandover True if the request is for IWLAN handover. - * @param linkProperties If {@code isHandover} is true, this is the link properties of the - * existing data connection, otherwise null. + * @param reason The reason for data setup. Must be {@link #REQUEST_REASON_NORMAL} or + * {@link #REQUEST_REASON_HANDOVER}. + * @param linkProperties If {@code reason} is {@link #REQUEST_REASON_HANDOVER}, this is the + * link properties of the existing data connection, otherwise null. * @param callback The result callback for this request. */ public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, boolean isHandover, + boolean allowRoaming, @SetupDataReason int reason, LinkProperties linkProperties, DataServiceCallback callback) { // The default implementation is to return unsupported. callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null); @@ -128,12 +159,12 @@ public abstract class DataService extends Service { * provided callback to notify the platform. * * @param cid Call id returned in the callback of {@link DataServiceProvider#setupDataCall( - * int, DataProfile, boolean, boolean, boolean, LinkProperties, DataServiceCallback)}. - * @param reasonRadioShutDown True if the deactivate request reason is device shut down. - * @param isHandover True if the request is for IWLAN handover. + * int, DataProfile, boolean, boolean, int, LinkProperties, DataServiceCallback)}. + * @param reason The reason for data deactivation. Must be {@link #REQUEST_REASON_NORMAL}, + * {@link #REQUEST_REASON_SHUTDOWN} or {@link #REQUEST_REASON_HANDOVER}. * @param callback The result callback for this request. */ - public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, + public void deactivateDataCall(int cid, @DeactivateDataReason int reason, DataServiceCallback callback) { // The default implementation is to return unsupported. callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); @@ -219,32 +250,29 @@ public abstract class DataService extends Service { public final DataProfile dataProfile; public final boolean isRoaming; public final boolean allowRoaming; - public final boolean isHandover; + public final int reason; public final LinkProperties linkProperties; public final IDataServiceCallback callback; SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, boolean isHandover, - LinkProperties linkProperties, IDataServiceCallback callback) { + boolean allowRoaming, int reason, LinkProperties linkProperties, + IDataServiceCallback callback) { this.accessNetworkType = accessNetworkType; this.dataProfile = dataProfile; this.isRoaming = isRoaming; this.allowRoaming = allowRoaming; this.linkProperties = linkProperties; - this.isHandover = isHandover; + this.reason = reason; this.callback = callback; } } private static final class DeactivateDataCallRequest { public final int cid; - public final boolean reasonRadioShutDown; - public final boolean isHandover; + public final int reason; public final IDataServiceCallback callback; - DeactivateDataCallRequest(int cid, boolean reasonRadioShutDown, boolean isHandover, - IDataServiceCallback callback) { + DeactivateDataCallRequest(int cid, int reason, IDataServiceCallback callback) { this.cid = cid; - this.reasonRadioShutDown = reasonRadioShutDown; - this.isHandover = isHandover; + this.reason = reason; this.callback = callback; } } @@ -311,7 +339,7 @@ public abstract class DataService extends Service { SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj; service.setupDataCall(setupDataCallRequest.accessNetworkType, setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming, - setupDataCallRequest.allowRoaming, setupDataCallRequest.isHandover, + setupDataCallRequest.allowRoaming, setupDataCallRequest.reason, setupDataCallRequest.linkProperties, new DataServiceCallback(setupDataCallRequest.callback)); @@ -321,8 +349,7 @@ public abstract class DataService extends Service { DeactivateDataCallRequest deactivateDataCallRequest = (DeactivateDataCallRequest) message.obj; service.deactivateDataCall(deactivateDataCallRequest.cid, - deactivateDataCallRequest.reasonRadioShutDown, - deactivateDataCallRequest.isHandover, + deactivateDataCallRequest.reason, new DataServiceCallback(deactivateDataCallRequest.callback)); break; case DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN: @@ -370,7 +397,8 @@ public abstract class DataService extends Service { } } - private DataService() { + /** @hide */ + protected DataService() { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); @@ -472,19 +500,18 @@ public abstract class DataService extends Service { @Override public void setupDataCall(int accessNetworkType, DataProfile dataProfile, - boolean isRoaming, boolean allowRoaming, boolean isHandover, + boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, IDataServiceCallback callback) { mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, mSlotId, 0, new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming, - allowRoaming, isHandover, linkProperties, callback)) + allowRoaming, reason, linkProperties, callback)) .sendToTarget(); } @Override - public void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, - IDataServiceCallback callback) { + public void deactivateDataCall(int cid, int reason, IDataServiceCallback callback) { mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, mSlotId, 0, - new DeactivateDataCallRequest(cid, reasonRadioShutDown, isHandover, callback)) + new DeactivateDataCallRequest(cid, reason, callback)) .sendToTarget(); } diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index 4eaaa252da02..07720b69e45f 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -26,10 +26,9 @@ import android.telephony.data.IDataServiceCallback; oneway interface IDataService { void setupDataCall(int accessNetwork, in DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, boolean isHandover, in LinkProperties linkProperties, + boolean allowRoaming, int reason, in LinkProperties linkProperties, IDataServiceCallback callback); - void deactivateDataCall(int cid, boolean reasonRadioShutDown, boolean isHandover, - IDataServiceCallback callback); + void deactivateDataCall(int cid, int reason, IDataServiceCallback callback); void setInitialAttachApn(in DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback); void setDataProfile(in List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback); diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java index 13e3693cada0..41cde175759d 100644 --- a/test-mock/src/android/test/mock/MockPackageManager.java +++ b/test-mock/src/android/test/mock/MockPackageManager.java @@ -108,6 +108,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public Intent getCarLaunchIntentForPackage(String packageName) { + throw new UnsupportedOperationException(); + } + @Override public int[] getPackageGids(String packageName) throws NameNotFoundException { throw new UnsupportedOperationException(); diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index d9d4eeba900f..1618e07a79c0 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -268,6 +268,31 @@ public class IpSecServiceParameterizedTest { anyInt()); } + public void testCreateTwoTransformsWithSameSpis() throws Exception { + IpSecConfig ipSecConfig = new IpSecConfig(); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); + + IpSecTransformResponse createTransformResp = + mIpSecService.createTransform(ipSecConfig, new Binder()); + assertEquals(IpSecManager.Status.OK, createTransformResp.status); + + // Attempting to create transform a second time with the same SPIs should throw an error... + try { + mIpSecService.createTransform(ipSecConfig, new Binder()); + fail("IpSecService should have thrown an error for reuse of SPI"); + } catch (IllegalStateException expected) { + } + + // ... even if the transform is deleted + mIpSecService.deleteTransform(createTransformResp.resourceId); + try { + mIpSecService.createTransform(ipSecConfig, new Binder()); + fail("IpSecService should have thrown an error for reuse of SPI"); + } catch (IllegalStateException expected) { + } + } + @Test public void testDeleteTransform() throws Exception { IpSecConfig ipSecConfig = new IpSecConfig(); |